true

Step 0: check and install needed packages. Load the libraries and functions.

packages.used=c("rvest", "tibble", "qdap", 
                "sentimentr", "gplots", "dplyr",
                "tm", "syuzhet", "factoextra", 
                "beeswarm", "scales", "RColorBrewer",
                "RANN", "tm", "topicmodels")
# check packages that need to be installed.
packages.needed=setdiff(packages.used, 
                        intersect(installed.packages()[,1], 
                                  packages.used))
# install additional packages
if(length(packages.needed)>0){
  install.packages(packages.needed, dependencies = TRUE)
}
# load packages
library("rvest")
library("tibble")
library("qdap")
library("sentimentr")
library("gplots")
library("dplyr")
library("tm")
library("syuzhet")
library("factoextra")
library("beeswarm")
library("scales")
library("RColorBrewer")
library("RANN")
library("tm")
library("topicmodels")
source("../lib/plotstacked.R")
source("../lib/speechFuncs.R")

This notebook was prepared with the following environmental settings.

print(R.version)
               _                           
platform       x86_64-apple-darwin13.4.0   
arch           x86_64                      
os             darwin13.4.0                
system         x86_64, darwin13.4.0        
status                                     
major          3                           
minor          3.1                         
year           2016                        
month          06                          
day            21                          
svn rev        70800                       
language       R                           
version.string R version 3.3.1 (2016-06-21)
nickname       Bug in Your Hair            

Step 1: Data harvest: scrap speech URLs from http://www.presidency.ucsb.edu/.

Following the example of Jerid Francom, we used Selectorgadget to choose the links we would like to scrap. For this project, we selected all inaugural addresses of past presidents, nomination speeches of major party candidates and farewell addresses. We also included several public speeches from Donald Trump for our textual analysis of presidential speeches.

### Inauguaral speeches
main.page <- read_html(x = "http://www.presidency.ucsb.edu/inaugurals.php")
# Get link URLs
# f.speechlinks is a function for extracting links from the list of speeches. 
inaug=f.speechlinks(main.page)
#head(inaug)
as.Date(inaug[,1], format="%B %e, %Y")
 [1] "1789-04-30" "1793-03-04" "1797-03-04" "1801-03-04" "1805-03-04" "1809-03-04" "1813-03-04"
 [8] "1817-03-04" "1821-03-04" "1825-03-04" "1829-03-04" "1833-03-04" "1837-03-04" "1841-03-04"
[15] "1845-03-04" "1849-03-05" "1853-03-04" "1857-03-04" "1861-03-04" "1865-03-04" "1869-03-04"
[22] "1873-03-04" "1877-03-05" "1881-03-04" "1885-03-04" "1889-03-04" "1893-03-04" "1897-03-04"
[29] "1901-03-04" "1905-03-04" "1909-03-04" "1913-03-04" "1917-03-04" "1921-03-04" "1925-03-04"
[36] "1929-03-04" "1933-03-04" "1937-01-20" "1941-01-20" "1945-01-20" "1949-01-20" "1953-01-20"
[43] "1957-01-21" "1961-01-20" "1965-01-20" "1969-01-20" "1973-01-20" "1977-01-20" "1981-01-20"
[50] "1985-01-21" "1989-01-20" "1993-01-20" "1997-01-20" "2001-01-20" "2005-01-20" "2009-01-20"
[57] "2013-01-21" "2017-01-20" NA          
inaug=inaug[-nrow(inaug),] # remove the last line, irrelevant due to error.
#### Nomination speeches
main.page=read_html("http://www.presidency.ucsb.edu/nomination.php")
# Get link URLs
nomin <- f.speechlinks(main.page)
#head(nomin)
#
#### Farewell speeches
main.page=read_html("http://www.presidency.ucsb.edu/farewell_addresses.php")
# Get link URLs
farewell <- f.speechlinks(main.page)
#head(farewell)

Step 2: Using speech metadata posted on http://www.presidency.ucsb.edu/, we prepared CSV data sets for the speeches we will scrap.

inaug.list=read.csv("../data/inauglist.csv", stringsAsFactors = FALSE)
nomin.list=read.csv("../data/nominlist.csv", stringsAsFactors = FALSE)
farewell.list=read.csv("../data/farewelllist.csv", stringsAsFactors = FALSE)

We assemble all scrapped speeches into one list. Note here that we don’t have the full text yet, only the links to full text transcripts.

Step 3: scrap the texts of speeches from the speech URLs.

speech.list=rbind(inaug.list, nomin.list, farewell.list)
speech.list$type=c(rep("inaug", nrow(inaug.list)),
                   rep("nomin", nrow(nomin.list)),
                   rep("farewell", nrow(farewell.list)))
speech.url=rbind(inaug, nomin, farewell)
speech.list=cbind(speech.list, speech.url)

Based on the list of speeches, we scrap the main text part of the transcript’s html page. For simple html pages of this kind, Selectorgadget is very convenient for identifying the html node that rvest can use to scrap its content. For reproducibility, we also save our scrapped speeches into our local folder as individual speech files.

# Loop over each row in speech.list
speech.list$fulltext=NA
for(i in seq(nrow(speech.list))) {
  text <- read_html(speech.list$urls[i]) %>% # load the page
    html_nodes(".displaytext") %>% # isloate the text
    html_text() # get the text
  speech.list$fulltext[i]=text
  # Create the file name
  filename <- paste0("../data/fulltext/", 
                     speech.list$type[i],
                     speech.list$File[i], "-", 
                     speech.list$Term[i], ".txt")
  sink(file = filename) %>% # open file to write 
  cat(text)  # write the file
  sink() # close the file
}

Trump, as president-elect that has not been a politician, do not have a lot of formal speeches yet. For our textual analysis, we manually add several public transcripts from Trump: + [Transcript: Donald Trump’s full immigration speech, annotated. LA Times, 08/31/2016] (http://www.latimes.com/politics/la-na-pol-donald-trump-immigration-speech-transcript-20160831-snap-htmlstory.html) + Transcript of Donald Trump’s speech on national security in Philadelphia - The Hill, 09/07/16 + Transcript of President-elect Trump’s news conference CNBC, 01/11/2017

speech1=paste(readLines("../data/fulltext/SpeechDonaldTrump-NA.txt", 
                  n=-1, skipNul=TRUE),
              collapse=" ")
speech2=paste(readLines("../data/fulltext/SpeechDonaldTrump-NA2.txt", 
                  n=-1, skipNul=TRUE),
              collapse=" ")
speech3=paste(readLines("../data/fulltext/PressDonaldTrump-NA.txt", 
                  n=-1, skipNul=TRUE),
              collapse=" ")
Trump.speeches=data.frame(
  President=rep("Donald J. Trump", 3),
  File=rep("DonaldJTrump", 3),
  Term=rep(0, 3),
  Party=rep("Republican", 3),
  Date=c("August 31, 2016", "September 7, 2016", "January 11, 2017"),
  Words=c(word_count(speech1), word_count(speech2), word_count(speech3)),
  Win=rep("yes", 3),
  type=rep("speeches", 3),
  links=rep(NA, 3),
  urls=rep(NA, 3),
  fulltext=c(speech1, speech2, speech3)
)
speech.list=rbind(speech.list, Trump.speeches)

Step 4: data Processing — generate list of sentences

We will use sentences as units of analysis for this project, as sentences are natural languge units for organizing thoughts and ideas. For each extracted sentence, we apply sentiment analysis using NRC sentiment lexion. “The NRC Emotion Lexicon is a list of English words and their associations with eight basic emotions (anger, fear, anticipation, trust, surprise, sadness, joy, and disgust) and two sentiments (negative and positive). The annotations were manually done by crowdsourcing.”

We assign an sequential id to each sentence in a speech (sent.id) and also calculated the number of words in each sentence as sentence length (word.count).

sentence.list=NULL
for(i in 1:nrow(speech.list)){
  sentences=sent_detect(speech.list$fulltext[i],
                        endmarks = c("?", ".", "!", "|",";"))
  if(length(sentences)>0){
    emotions=get_nrc_sentiment(sentences)
    word.count=word_count(sentences)
    # colnames(emotions)=paste0("emo.", colnames(emotions))
    # in case the word counts are zeros?
    emotions=diag(1/(word.count+0.01))%*%as.matrix(emotions)
    sentence.list=rbind(sentence.list, 
                        cbind(speech.list[i,-ncol(speech.list)],
                              sentences=as.character(sentences), 
                              word.count,
                              emotions,
                              sent.id=1:length(sentences)
                              )
    )
  }
}

Some non-sentences exist in raw data due to erroneous extra end-of sentence marks.

sentence.list=
  sentence.list%>%
  filter(!is.na(word.count)) 

Step 5: Data analysis — length of sentences

For simpler visualization, we chose a subset of better known presidents or presidential candidates on which to focus our analysis.

sel.comparison=c("DonaldJTrump","JohnMcCain", "GeorgeBush", "MittRomney", "GeorgeWBush",
                 "RonaldReagan","AlbertGore,Jr", "HillaryClinton","JohnFKerry", 
                 "WilliamJClinton","HarrySTruman", "BarackObama", "LyndonBJohnson",
                 "GeraldRFord", "JimmyCarter", "DwightDEisenhower", "FranklinDRoosevelt",
                 "HerbertHoover","JohnFKennedy","RichardNixon","WoodrowWilson", 
                 "AbrahamLincoln", "TheodoreRoosevelt", "JamesGarfield", 
                 "JohnQuincyAdams", "UlyssesSGrant", "ThomasJefferson",
                 "GeorgeWashington", "WilliamHowardTaft", "AndrewJackson",
                 "WilliamHenryHarrison", "JohnAdams")

Overview of sentence length distribution by different types of speeches.

Nomination speeches

First, we look at nomination acceptance speeches at major party’s national conventions. For relevant to Trump’s speeches, we limit our attention to speeches for the first terms of former U.S. presidents. We noticed that a number of presidents have very short sentences in their nomination acceptance speeches.

First term

par(mar=c(4, 11, 2, 2))
#sel.comparison=levels(sentence.list$FileOrdered)
sentence.list.sel=filter(sentence.list, 
                        type=="nomin", Term==1, File%in%sel.comparison)
sentence.list.sel$File=factor(sentence.list.sel$File)
sentence.list.sel$FileOrdered=reorder(sentence.list.sel$File, 
                                  sentence.list.sel$word.count, 
                                  mean, 
                                  order=T)
beeswarm(word.count~FileOrdered, 
         data=sentence.list.sel,
         horizontal = TRUE, 
         pch=16, col=alpha(brewer.pal(9, "Set1"), 0.6), 
         cex=0.55, cex.axis=0.8, cex.lab=0.8,
         spacing=5/nlevels(sentence.list.sel$FileOrdered),
         las=2, xlab="Number of words in a sentence.", ylab="",
         main="Nomination speeches")

Second term

par(mar=c(4, 11, 2, 2))
#sel.comparison=levels(sentence.list$FileOrdered)
sentence.list.sel=filter(sentence.list, 
                        type=="nomin", Term==2, File%in%sel.comparison)
sentence.list.sel$File=factor(sentence.list.sel$File)
sentence.list.sel$FileOrdered=reorder(sentence.list.sel$File, 
                                  sentence.list.sel$word.count, 
                                  mean, 
                                  order=T)
beeswarm(word.count~FileOrdered, 
         data=sentence.list.sel,
         horizontal = TRUE, 
         pch=16, col=alpha(brewer.pal(9, "Set1"), 0.6), 
         cex=0.55, cex.axis=0.8, cex.lab=0.8,
         spacing=1.2/nlevels(sentence.list.sel$FileOrdered),
         las=2, xlab="Number of words in a sentence.", ylab="",
         main="Nomination speeches, 2nd term")

What are these short sentences?

sentence.list%>%
  filter(File=="DonaldJTrump", 
         type=="nomin", 
         word.count<=3)%>%
  select(sentences)%>%sample_n(10)
sentence.list%>%
  filter(File=="AlbertGore,Jr", 
         type=="nomin", 
         word.count<=3)%>%
  select(sentences)%>%sample_n(10)
sentence.list%>%
  filter(File=="Clinton", 
         type=="nomin", 
         word.count<=3)%>%
  select(sentences)
sentence.list%>%
  filter(File=="WilliamJClinton", 
         type=="nomin", Term==1,
         word.count<=3)%>%
  select(sentences)

Inaugural speeches

We notice that the sentences in inaugural speeches are longer than those in nomination acceptance speeches.

sentence.list.sel=sentence.list%>%filter(type=="inaug", File%in%sel.comparison, Term==1)
sentence.list.sel$File=factor(sentence.list.sel$File)
sentence.list.sel$FileOrdered=reorder(sentence.list.sel$File, 
                                  sentence.list.sel$word.count, 
                                  mean, 
                                  order=T)
par(mar=c(4, 11, 2, 2))
beeswarm(word.count~FileOrdered, 
         data=sentence.list.sel,
         horizontal = TRUE,
         pch=16, col=alpha(brewer.pal(9, "Set1"), 0.6), 
         cex=0.55, cex.axis=0.8, cex.lab=0.8,
         spacing=5/nlevels(sentence.list.sel$FileOrdered),
         las=2, ylab="", xlab="Number of words in a sentence.",
         main="Inaugural Speeches")

Short sentences in inaugural speeches.

sentence.list%>%
  filter(File=="BarackObama", 
         type=="inaug", 
         word.count<=3)%>%
  select(sentences)

Step 5: Data analysis — sentiment analsis

Sentence length variation over the course of the speech, with emotions.

How our presidents (or candidates) alternate between long and short sentences and how they shift between different sentiments in their speeches. It is interesting to note that some presidential candidates’ speech are more colorful than others. Here we used the same color theme as in the movie “Inside Out.”

image

image

par(mfrow=c(4,1), mar=c(1,0,2,0), bty="n", xaxt="n", yaxt="n", font.main=1)
f.plotsent.len(In.list=sentence.list, InFile="HillaryClinton", 
               InType="nomin", InTerm=1, President="Hillary Clinton")
f.plotsent.len(In.list=sentence.list, InFile="DonaldJTrump", 
               InType="nomin", InTerm=1, President="Donald Trump")
f.plotsent.len(In.list=sentence.list, InFile="BarackObama", 
               InType="nomin", InTerm=1, President="Barack Obama")
f.plotsent.len(In.list=sentence.list, InFile="GeorgeWBush", 
               InType="nomin", InTerm=1, President="George W. Bush")

What are the emotionally charged sentences?

print("Hillary Clinton")
[1] "Hillary Clinton"
speech.df=tbl_df(sentence.list)%>%
  filter(File=="HillaryClinton", type=="nomin", word.count>=4)%>%
  select(sentences, anger:trust)
speech.df=as.data.frame(speech.df)
as.character(speech.df$sentences[apply(speech.df[,-1], 2, which.max)])
[1] "Some of you are frustrated, even furious."                        
[2] "It's a big deal."                                                 
[3] "Powerful forces are threatening to pull us apart."                
[4] "Powerful forces are threatening to pull us apart."                
[5] "It's a big deal."                                                 
[6] "My mother, Dorothy, was abandoned by her parents as a young girl."
[7] "It's a big deal."                                                 
[8] "Bonds of trust and respect are fraying."                          
print("Barack Obama")
[1] "Barack Obama"
speech.df=tbl_df(sentence.list)%>%
  filter(File=="BarackObama", type=="nomin", Term==1, word.count>=5)%>%
  select(sentences, anger:trust)
speech.df=as.data.frame(speech.df)
as.character(speech.df$sentences[apply(speech.df[,-1], 2, which.max)])
[1] "They could've heard words of anger and discord."
[2] "And that's to be expected."                     
[3] "It's not because John McCain doesn't care."     
[4] "Now let there be no doubt."                     
[5] "That promise is our greatest inheritance."      
[6] "Now let there be no doubt."                     
[7] "That's not the judgment we need."               
[8] "That promise is our greatest inheritance."      
print("George W Bush")
[1] "George W Bush"
speech.df=tbl_df(sentence.list)%>%
  filter(File=="GeorgeWBush", type=="nomin", Term==1, word.count>=4)%>%
  select(sentences, anger:trust)
speech.df=as.data.frame(speech.df)
as.character(speech.df$sentences[apply(speech.df[,-1], 2, which.max)])
[1] "On the other side of that wall are poverty and prison, addiction and despair."                                           
[2] "We're proud of you."                                                                                                     
[3] "But they've got it backwards."                                                                                           
[4] "And at the earliest possible date, my administration will deploy missile defenses to guard against attack and blackmail."
[5] "I appreciate his friendship."                                                                                            
[6] "On the other side of that wall are poverty and prison, addiction and despair."                                           
[7] "They had their chance."                                                                                                  
[8] "Corporations are responsible to treat their workers fairly and to leave the air and waters clean."                       
print("Donald Trump")
[1] "Donald Trump"
speech.df=tbl_df(sentence.list)%>%
  filter(File=="DonaldJTrump", type=="nomin", Term==1, word.count>=5)%>%
  select(sentences, anger:trust)
speech.df=as.data.frame(speech.df)
as.character(speech.df$sentences[apply(speech.df[,-1], 2, which.max)])
[1] "Once again, France is the victim of brutal Islamic terrorism."                                                   
[2] "God bless you, and good night!"                                                                                  
[3] "I have visited the laid-off factory workers, and the communities crushed by our horrible and unfair trade deals."
[4] "Once again, France is the victim of brutal Islamic terrorism."                                                   
[5] "God bless you, and good night!"                                                                                  
[6] "Three were killed, and three were very very badly injured."                                                      
[7] "God bless you, and good night!"                                                                                  
[8] "God bless you, and good night!"                                                                                  

Clustering of emotions

heatmap.2(cor(sentence.list%>%filter(type=="inaug")%>%select(anger:trust)), 
          scale = "none", 
          col = bluered(100), , margin=c(6, 6), key=F,
          trace = "none", density.info = "none")
par(mar=c(4, 6, 2, 1))

emo.means=colMeans(select(sentence.list, anger:trust)>0.01)
col.use=c("red2", "darkgoldenrod1", 
            "chartreuse3", "blueviolet",
            "darkgoldenrod2", "dodgerblue3", 
            "darkgoldenrod1", "darkgoldenrod1")
barplot(emo.means[order(emo.means)], las=2, col=col.use[order(emo.means)], horiz=T, main="Inaugural Speeches")

presid.summary=tbl_df(sentence.list)%>%
  filter(type=="nomin", File%in%sel.comparison)%>%
  #group_by(paste0(type, File))%>%
  group_by(File)%>%
  summarise(
    anger=mean(anger),
    anticipation=mean(anticipation),
    disgust=mean(disgust),
    fear=mean(fear),
    joy=mean(joy),
    sadness=mean(sadness),
    surprise=mean(surprise),
    trust=mean(trust)
    #negative=mean(negative),
    #positive=mean(positive)
  )
presid.summary=as.data.frame(presid.summary)
rownames(presid.summary)=as.character((presid.summary[,1]))
km.res=kmeans(presid.summary[,-1], iter.max=200,
              5)
fviz_cluster(km.res, 
             stand=F, repel= TRUE,
             data = presid.summary[,-1], xlab="", xaxt="n",
             show.clust.cent=FALSE)

Step 5: Data analysis — Topic modeling

For topic modeling, we prepare a corpus of sentence snipets as follows. For each speech, we start with sentences and prepare a snipet with a given sentence with the flanking sentences.

corpus.list=sentence.list[2:(nrow(sentence.list)-1), ]
sentence.pre=sentence.list$sentences[1:(nrow(sentence.list)-2)]
sentence.post=sentence.list$sentences[3:(nrow(sentence.list)-1)]
corpus.list$snipets=paste(sentence.pre, corpus.list$sentences, sentence.post, sep=" ")
rm.rows=(1:nrow(corpus.list))[corpus.list$sent.id==1]
rm.rows=c(rm.rows, rm.rows-1)
corpus.list=corpus.list[-rm.rows, ]

Text mining

docs <- Corpus(VectorSource(corpus.list$snipets))
writeLines(as.character(docs[[sample(1:nrow(corpus.list), 1)]]))
It is in this spirit that we demand adequate provision for national defense, and we condemn the inexcusable neglect that has been shown in this matter of first national importance. We must have the strength which self-respect demands, the strength of an efficient nation ready for every emergency. Our preparation must be industrial and economical as well.

Text basic processing

Adapted from https://eight2late.wordpress.com/2015/09/29/a-gentle-introduction-to-topic-modeling-using-r/.

#remove potentially problematic symbols
docs <-tm_map(docs,content_transformer(tolower))
writeLines(as.character(docs[[sample(1:nrow(corpus.list), 1)]]))
it covers by its position in the gulf the mississippi and other great waters within our extended limits, and thereby enables the united states to afford complete protection to the vast and very valuable productions of our whole western country, which find a market through those streams. by a treaty with the british government, bearing date on the 20th of october, 1818, the convention regulating the commerce between the united states and great britain, concluded on the 3d of july, 1815, which was about expiring, was revived and continued for the term of ten years from the time of its expiration. by that treaty, also, the differences which had arisen under the treaty of ghent respecting the right claimed by the united states for their citizens to take and cure fish on the coast of his britannic majesty's dominions in america, with other differences on important interests, were adjusted to the satisfaction of both parties.
#remove punctuation
docs <- tm_map(docs, removePunctuation)
writeLines(as.character(docs[[sample(1:nrow(corpus.list), 1)]]))
i propose to you my friends and through you that government of all kinds big and little be made solvent and that the example be set by the president of the united states and his cabinet and talking about setting a definite example i congratulate this convention for having had the courage fearlessly to write into its declaration of principles what an overwhelming majority here assembled really thinks about the 18th amendment this convention wants repeal
#Strip digits
docs <- tm_map(docs, removeNumbers)
writeLines(as.character(docs[[sample(1:nrow(corpus.list), 1)]]))
that platform will be the heart of the message i will take to the country after january th it will be the cornerstone of our republican administration fortunately we are a united party
#remove stopwords
docs <- tm_map(docs, removeWords, stopwords("english"))
writeLines(as.character(docs[[sample(1:nrow(corpus.list), 1)]]))
  will say nothing   campaign  might destroy  chance    war   ended   people choose  november  choice will  clear   
#remove whitespace
docs <- tm_map(docs, stripWhitespace)
writeLines(as.character(docs[[sample(1:nrow(corpus.list), 1)]]))
 happens democrats must will rightly morally enable states protect importation intoxicating liquor importation may violate state laws must rightly morally prevent return saloon go back dry subject finance ties togetherthe th amendment something finance tooin comprehensive planning reconstruction great credit groups including government credit list important place prize statement principle platform adopted calling letting light day issues securities foreign domestic offered sale investing public
#Stem document
docs <- tm_map(docs,stemDocument)
writeLines(as.character(docs[[sample(1:nrow(corpus.list), 1)]]))
 time avoid mistak help found sustain unit nation weld allianc includ greater part free world

Topic modeling

Gengerate document-term matrices.

dtm <- DocumentTermMatrix(docs)
#convert rownames to filenames#convert rownames to filenames
rownames(dtm) <- paste(corpus.list$type, corpus.list$File,
                       corpus.list$Term, corpus.list$sent.id, sep="_")
rowTotals <- apply(dtm , 1, sum) #Find the sum of words in each Document
dtm  <- dtm[rowTotals> 0, ]
corpus.list=corpus.list[rowTotals>0, ]

Run LDA

#Set parameters for Gibbs sampling
burnin <- 4000
iter <- 2000
thin <- 500
seed <-list(2003,5,63,100001,765)
nstart <- 5
best <- TRUE
#Number of topics
k <- 15
#Run LDA using Gibbs sampling
ldaOut <-LDA(dtm, k, method="Gibbs", control=list(nstart=nstart, 
                                                 seed = seed, best=best,
                                                 burnin = burnin, iter = iter, 
                                                 thin=thin))
terms.beta=ldaOut@beta
terms.beta=scale(terms.beta)
topics.terms=NULL
for(i in 1:k){
  topics.terms=rbind(topics.terms, ldaOut@terms[order(terms.beta[i,], decreasing = TRUE)[1:7]])
}
topics.terms
ldaOut.terms

Based on the most popular terms and the most salient terms for each topic, we assign a hashtag to each topic. This part require manual setup as the topics are likely to change.

topics.hash=c("Economy", "America", "Defense", "Belief", "Election", "Patriotism", "Unity", "Government", "Reform", "Temporal", "WorkingFamilies", "Freedom", "Equality", "Misc", "Legislation")
corpus.list$ldatopic=as.vector(ldaOut.topics)
corpus.list$ldahash=topics.hash[ldaOut.topics]

colnames(topicProbabilities)=topics.hash
corpus.list.df=cbind(corpus.list, topicProbabilities)

Clustering of topics

par(mar=c(1,1,1,1))
topic.summary=tbl_df(corpus.list.df)%>%
              filter(type%in%c("nomin", "inaug"), File%in%sel.comparison)%>%
              select(File, Economy:Legislation)%>%
              group_by(File)%>%
              summarise_each(funs(mean))
topic.summary=as.data.frame(topic.summary)
rownames(topic.summary)=topic.summary[,1]

# [1] "Economy"         "America"         "Defense"         "Belief"         
# [5] "Election"        "Patriotism"      "Unity"           "Government"     
# [9] "Reform"          "Temporal"        "WorkingFamilies" "Freedom"        
# [13] "Equality"        "Misc"            "Legislation"       

topic.plot=c(1, 13, 9, 11, 8, 3, 7)
print(topics.hash[topic.plot])

heatmap.2(as.matrix(topic.summary[,topic.plot+1]), 
          scale = "column", key=F, 
          col = bluered(100),
          cexRow = 0.9, cexCol = 0.9, margins = c(8, 8),
          trace = "none", density.info = "none")
# [1] "Economy"         "America"         "Defense"         "Belief"         
# [5] "Election"        "Patriotism"      "Unity"           "Government"     
# [9] "Reform"          "Temporal"        "WorkingFamilies" "Freedom"        
# [13] "Equality"        "Misc"            "Legislation"       
 

par(mfrow=c(5, 1), mar=c(1,1,2,0), bty="n", xaxt="n", yaxt="n")

topic.plot=c(1, 13, 14, 15, 8, 9, 12)
print(topics.hash[topic.plot])

speech.df=tbl_df(corpus.list.df)%>%filter(File=="GeorgeBush", type=="nomin",Term==1)%>%select(sent.id, Economy:Legislation)
speech.df=as.matrix(speech.df)
speech.df[,-1]=replace(speech.df[,-1], speech.df[,-1]<1/15, 0.001)
speech.df[,-1]=f.smooth.topic(x=speech.df[,1], y=speech.df[,-1])
plot.stacked(speech.df[,1], speech.df[,topic.plot+1], 
             xlab="Sentences", ylab="Topic share", main="George Bush, Nomination")

speech.df=tbl_df(corpus.list.df)%>%filter(File=="WilliamJClinton", type=="nomin", Term==1)%>%select(sent.id, Economy:Legislation)
speech.df=as.matrix(speech.df)
speech.df[,-1]=replace(speech.df[,-1], speech.df[,-1]<1/15, 0.001)
speech.df[,-1]=f.smooth.topic(x=speech.df[,1], y=speech.df[,-1])
plot.stacked(speech.df[,1], speech.df[,topic.plot+1],
            xlab="Sentences", ylab="Topic share", main="Bill Clinton, Nomination")

speech.df=tbl_df(corpus.list.df)%>%filter(File=="GeorgeWBush", type=="nomin", Term==1)%>%select(sent.id, Economy:Legislation)
speech.df=as.matrix(speech.df)
speech.df[,-1]=replace(speech.df[,-1], speech.df[,-1]<1/15, 0.001)
speech.df[,-1]=f.smooth.topic(x=speech.df[,1], y=speech.df[,-1])
plot.stacked(speech.df[,1], speech.df[,topic.plot+1], 
            xlab="Sentences", ylab="Topic share", main="George W Bush, Nomination")

speech.df=tbl_df(corpus.list.df)%>%filter(File=="BarackObama", type=="nomin", Term==1)%>%select(sent.id, Economy:Legislation)
speech.df=as.matrix(speech.df)
speech.df[,-1]=replace(speech.df[,-1], speech.df[,-1]<1/15, 0.001)
speech.df[,-1]=f.smooth.topic(x=speech.df[,1], y=speech.df[,-1])
plot.stacked(speech.df[,1], speech.df[,topic.plot+1],
            xlab="Sentences", ylab="Topic share", main="Barack Obama, Nomination")

speech.df=tbl_df(corpus.list.df)%>%filter(File=="DonaldJTrump", type=="nomin")%>%select(sent.id, Economy:Legislation)
speech.df=as.matrix(speech.df)
speech.df[,-1]=replace(speech.df[,-1], speech.df[,-1]<1/15, 0.001)
speech.df[,-1]=f.smooth.topic(x=speech.df[,1], y=speech.df[,-1])
plot.stacked(speech.df[,1], speech.df[,topic.plot+1],
            xlab="Sentences", ylab="Topic share", main="Donald Trump, Nomination")
# [1] "Economy"         "America"         "Defense"         "Belief"         
# [5] "Election"        "Patriotism"      "Unity"           "Government"     
# [9] "Reform"          "Temporal"        "WorkingFamilies" "Freedom"        
# [13] "Equality"        "Misc"            "Legislation"       


par(mfrow=c(5, 1), mar=c(1,1,2,0), bty="n", xaxt="n", yaxt="n")


topic.plot=c(1, 13, 14, 15, 8, 9, 12)
print(topics.hash[topic.plot])

speech.df=tbl_df(corpus.list.df)%>%filter(File=="GeorgeBush", type=="inaug", Term==1)%>%select(sent.id, Economy:Legislation)
speech.df=as.matrix(speech.df)
speech.df[,-1]=replace(speech.df[,-1], speech.df[,-1]<1/15, 0.001)
speech.df[,-1]=f.smooth.topic(x=speech.df[,1], y=speech.df[,-1])
plot.stacked(speech.df[,1], speech.df[,topic.plot+1],
             xlab="Sentences", ylab="Topic share", main="George Bush, inaugural Speeches")

speech.df=tbl_df(corpus.list.df)%>%filter(File=="WilliamJClinton", type=="inaug", Term==1)%>%select(sent.id, Economy:Legislation)
speech.df=as.matrix(speech.df)
speech.df[,-1]=replace(speech.df[,-1], speech.df[,-1]<1/15, 0.001)
speech.df[,-1]=f.smooth.topic(x=speech.df[,1], y=speech.df[,-1])
plot.stacked(speech.df[,1], speech.df[,topic.plot+1],
             xlab="Sentences", ylab="Topic share", main="William J Clinton, inaugural Speeches")

speech.df=tbl_df(corpus.list.df)%>%filter(File=="GeorgeWBush", type=="inaug", Term==1)%>%select(sent.id, Economy:Legislation)
speech.df=as.matrix(speech.df)
speech.df[,-1]=replace(speech.df[,-1], speech.df[,-1]<1/15, 0.001)
speech.df[,-1]=f.smooth.topic(x=speech.df[,1], y=speech.df[,-1])
plot.stacked(speech.df[,1], speech.df[,topic.plot+1],
             xlab="Sentences", ylab="Topic share", main="George W. Bush, inaugural Speeches")

speech.df=tbl_df(corpus.list.df)%>%filter(File=="BarackObama", type=="inaug", Term==1)%>%select(sent.id, Economy:Legislation)
speech.df=as.matrix(speech.df)
speech.df[,-1]=replace(speech.df[,-1], speech.df[,-1]<1/15, 0.001)
speech.df[,-1]=f.smooth.topic(x=speech.df[,1], y=speech.df[,-1])
plot.stacked(speech.df[,1], speech.df[,topic.plot+1],
             xlab="Sentences", ylab="Topic share", main="Barack Obama, inaugural Speeches")
# [1] "Economy"         "America"         "Defense"         "Belief"         
# [5] "Election"        "Patriotism"      "Unity"           "Government"     
# [9] "Reform"          "Temporal"        "WorkingFamilies" "Freedom"        
# [13] "Equality"        "Misc"            "Legislation"       


par(mfrow=c(5, 1))

topic.plot=c(1, 13, 14, 15, 8, 9, 12)
print(topics.hash[topic.plot])

speech.df=tbl_df(corpus.list.df)%>%filter(File=="RonaldReagan", type=="farewell")%>%select(sent.id, Economy:Legislation)
speech.df=as.matrix(speech.df)
speech.df[,-1]=replace(speech.df[,-1], speech.df[,-1]<1/15, 0.001)
speech.df[,-1]=f.smooth.topic(x=speech.df[,1], y=speech.df[,-1])
plot.stacked(speech.df[,1], speech.df[,topic.plot+1],
             xlab="Sentences", ylab="Topic share", main="Ronald Reagan, Farewell Speeches")

speech.df=tbl_df(corpus.list.df)%>%filter(File=="GeorgeBush", type=="farewell")%>%select(sent.id, Economy:Legislation)
speech.df=as.matrix(speech.df)
speech.df[,-1]=replace(speech.df[,-1], speech.df[,-1]<1/15, 0.001)
speech.df[,-1]=f.smooth.topic(x=speech.df[,1], y=speech.df[,-1])
plot.stacked(speech.df[,1], speech.df[,topic.plot+1],
             xlab="Sentences", ylab="Topic share", main="George Bush, Farewell Speeches")

speech.df=tbl_df(corpus.list.df)%>%filter(File=="WilliamJClinton", type=="farewell")%>%select(sent.id, Economy:Legislation)
speech.df=as.matrix(speech.df)
speech.df[,-1]=replace(speech.df[,-1], speech.df[,-1]<1/15, 0.001)
speech.df[,-1]=f.smooth.topic(x=speech.df[,1], y=speech.df[,-1])
plot.stacked(speech.df[,1], speech.df[,topic.plot+1],
             xlab="Sentences", ylab="Topic share", main="William J. Clinton, Farewell Speeches")

speech.df=tbl_df(corpus.list.df)%>%filter(File=="GeorgeWBush", type=="farewell")%>%select(sent.id, Economy:Legislation)
speech.df=as.matrix(speech.df)
speech.df[,-1]=replace(speech.df[,-1], speech.df[,-1]<1/15, 0.001)
speech.df[,-1]=f.smooth.topic(x=speech.df[,1], y=speech.df[,-1])
plot.stacked(speech.df[,1], speech.df[,topic.plot+1],
             xlab="Sentences", ylab="Topic share", main="George W Bush, Farewell Speeches")


speech.df=tbl_df(corpus.list.df)%>%filter(File=="BarackObama", type=="farewell")%>%select(sent.id, Economy:Legislation)
speech.df=as.matrix(speech.df)
speech.df[,-1]=replace(speech.df[,-1], speech.df[,-1]<1/15, 0.001)
speech.df[,-1]=f.smooth.topic(x=speech.df[,1], y=speech.df[,-1])
plot.stacked(speech.df[,1], speech.df[,topic.plot+1],
             xlab="Sentences", ylab="Topic share", main="Barack Obama, Farewell Speeches")
speech.df=tbl_df(corpus.list.df)%>%filter(type=="nomin", word.count<20)%>%select(sentences, Economy:Legislation)

as.character(speech.df$sentences[apply(as.data.frame(speech.df[,-1]), 2, which.max)])

names(speech.df)[-1]
presid.summary=tbl_df(corpus.list.df)%>%
  filter(type=="inaug", File%in%sel.comparison)%>%
  select(File, Economy:Legislation)%>%
  group_by(File)%>%
  summarise_each(funs(mean))

presid.summary=as.data.frame(presid.summary)
rownames(presid.summary)=as.character((presid.summary[,1]))
km.res=kmeans(scale(presid.summary[,-1]), iter.max=200,
              5)
fviz_cluster(km.res, 
             stand=T, repel= TRUE,
             data = presid.summary[,-1],
             show.clust.cent=FALSE)
LS0tCnRpdGxlOiAiVHV0b3JpYWwgKHdlZWsgMikgQjogdGV4dCBtaW5pbmciCm91dHB1dDogaHRtbF9ub3RlYm9vawp0b2M6IHRydWUKdG9jX2RlcHRoOiAyCi0tLQoKIyBTdGVwIDA6IGNoZWNrIGFuZCBpbnN0YWxsIG5lZWRlZCBwYWNrYWdlcy4gTG9hZCB0aGUgbGlicmFyaWVzIGFuZCBmdW5jdGlvbnMuIAoKYGBge3IsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CnBhY2thZ2VzLnVzZWQ9YygicnZlc3QiLCAidGliYmxlIiwgInFkYXAiLCAKICAgICAgICAgICAgICAgICJzZW50aW1lbnRyIiwgImdwbG90cyIsICJkcGx5ciIsCiAgICAgICAgICAgICAgICAidG0iLCAic3l1emhldCIsICJmYWN0b2V4dHJhIiwgCiAgICAgICAgICAgICAgICAiYmVlc3dhcm0iLCAic2NhbGVzIiwgIlJDb2xvckJyZXdlciIsCiAgICAgICAgICAgICAgICAiUkFOTiIsICJ0bSIsICJ0b3BpY21vZGVscyIpCgojIGNoZWNrIHBhY2thZ2VzIHRoYXQgbmVlZCB0byBiZSBpbnN0YWxsZWQuCnBhY2thZ2VzLm5lZWRlZD1zZXRkaWZmKHBhY2thZ2VzLnVzZWQsIAogICAgICAgICAgICAgICAgICAgICAgICBpbnRlcnNlY3QoaW5zdGFsbGVkLnBhY2thZ2VzKClbLDFdLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhY2thZ2VzLnVzZWQpKQojIGluc3RhbGwgYWRkaXRpb25hbCBwYWNrYWdlcwppZihsZW5ndGgocGFja2FnZXMubmVlZGVkKT4wKXsKICBpbnN0YWxsLnBhY2thZ2VzKHBhY2thZ2VzLm5lZWRlZCwgZGVwZW5kZW5jaWVzID0gVFJVRSkKfQoKIyBsb2FkIHBhY2thZ2VzCmxpYnJhcnkoInJ2ZXN0IikKbGlicmFyeSgidGliYmxlIikKbGlicmFyeSgicWRhcCIpCmxpYnJhcnkoInNlbnRpbWVudHIiKQpsaWJyYXJ5KCJncGxvdHMiKQpsaWJyYXJ5KCJkcGx5ciIpCmxpYnJhcnkoInRtIikKbGlicmFyeSgic3l1emhldCIpCmxpYnJhcnkoImZhY3RvZXh0cmEiKQpsaWJyYXJ5KCJiZWVzd2FybSIpCmxpYnJhcnkoInNjYWxlcyIpCmxpYnJhcnkoIlJDb2xvckJyZXdlciIpCmxpYnJhcnkoIlJBTk4iKQpsaWJyYXJ5KCJ0bSIpCmxpYnJhcnkoInRvcGljbW9kZWxzIikKCnNvdXJjZSgiLi4vbGliL3Bsb3RzdGFja2VkLlIiKQpzb3VyY2UoIi4uL2xpYi9zcGVlY2hGdW5jcy5SIikKYGBgClRoaXMgbm90ZWJvb2sgd2FzIHByZXBhcmVkIHdpdGggdGhlIGZvbGxvd2luZyBlbnZpcm9ubWVudGFsIHNldHRpbmdzLgoKYGBge3J9CnByaW50KFIudmVyc2lvbikKYGBgCgojIFN0ZXAgMTogRGF0YSBoYXJ2ZXN0OiBzY3JhcCBzcGVlY2ggVVJMcyBmcm9tIDxodHRwOi8vd3d3LnByZXNpZGVuY3kudWNzYi5lZHUvPi4KCkZvbGxvd2luZyB0aGUgZXhhbXBsZSBvZiBbSmVyaWQgRnJhbmNvbV0oaHR0cDovL2ZyYW5jb2pjLmdpdGh1Yi5pby93ZWItc2NyYXBpbmctd2l0aC1ydmVzdC8pLCB3ZSB1c2VkIFtTZWxlY3RvcmdhZGdldF0oaHR0cDovL3NlbGVjdG9yZ2FkZ2V0LmNvbS8pIHRvIGNob29zZSB0aGUgbGlua3Mgd2Ugd291bGQgbGlrZSB0byBzY3JhcC4gRm9yIHRoaXMgcHJvamVjdCwgd2Ugc2VsZWN0ZWQgYWxsIGluYXVndXJhbCBhZGRyZXNzZXMgb2YgcGFzdCBwcmVzaWRlbnRzLCBub21pbmF0aW9uIHNwZWVjaGVzIG9mIG1ham9yIHBhcnR5IGNhbmRpZGF0ZXMgYW5kIGZhcmV3ZWxsIGFkZHJlc3Nlcy4gV2UgYWxzbyBpbmNsdWRlZCBzZXZlcmFsIHB1YmxpYyBzcGVlY2hlcyBmcm9tIERvbmFsZCBUcnVtcCBmb3Igb3VyIHRleHR1YWwgYW5hbHlzaXMgb2YgcHJlc2lkZW50aWFsIHNwZWVjaGVzLiAKCmBgYHtyLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQojIyMgSW5hdWd1YXJhbCBzcGVlY2hlcwptYWluLnBhZ2UgPC0gcmVhZF9odG1sKHggPSAiaHR0cDovL3d3dy5wcmVzaWRlbmN5LnVjc2IuZWR1L2luYXVndXJhbHMucGhwIikKIyBHZXQgbGluayBVUkxzCiMgZi5zcGVlY2hsaW5rcyBpcyBhIGZ1bmN0aW9uIGZvciBleHRyYWN0aW5nIGxpbmtzIGZyb20gdGhlIGxpc3Qgb2Ygc3BlZWNoZXMuIAppbmF1Zz1mLnNwZWVjaGxpbmtzKG1haW4ucGFnZSkKI2hlYWQoaW5hdWcpCmFzLkRhdGUoaW5hdWdbLDFdLCBmb3JtYXQ9IiVCICVlLCAlWSIpCmluYXVnPWluYXVnWy1ucm93KGluYXVnKSxdICMgcmVtb3ZlIHRoZSBsYXN0IGxpbmUsIGlycmVsZXZhbnQgZHVlIHRvIGVycm9yLgoKIyMjIyBOb21pbmF0aW9uIHNwZWVjaGVzCm1haW4ucGFnZT1yZWFkX2h0bWwoImh0dHA6Ly93d3cucHJlc2lkZW5jeS51Y3NiLmVkdS9ub21pbmF0aW9uLnBocCIpCiMgR2V0IGxpbmsgVVJMcwpub21pbiA8LSBmLnNwZWVjaGxpbmtzKG1haW4ucGFnZSkKI2hlYWQobm9taW4pCiMKIyMjIyBGYXJld2VsbCBzcGVlY2hlcwptYWluLnBhZ2U9cmVhZF9odG1sKCJodHRwOi8vd3d3LnByZXNpZGVuY3kudWNzYi5lZHUvZmFyZXdlbGxfYWRkcmVzc2VzLnBocCIpCiMgR2V0IGxpbmsgVVJMcwpmYXJld2VsbCA8LSBmLnNwZWVjaGxpbmtzKG1haW4ucGFnZSkKI2hlYWQoZmFyZXdlbGwpCmBgYAoKIyBTdGVwIDI6IFVzaW5nIHNwZWVjaCBtZXRhZGF0YSBwb3N0ZWQgb24gPGh0dHA6Ly93d3cucHJlc2lkZW5jeS51Y3NiLmVkdS8+LCB3ZSBwcmVwYXJlZCBDU1YgZGF0YSBzZXRzIGZvciB0aGUgc3BlZWNoZXMgd2Ugd2lsbCBzY3JhcC4gCgpgYGB7cn0KaW5hdWcubGlzdD1yZWFkLmNzdigiLi4vZGF0YS9pbmF1Z2xpc3QuY3N2Iiwgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFKQpub21pbi5saXN0PXJlYWQuY3N2KCIuLi9kYXRhL25vbWlubGlzdC5jc3YiLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpCmZhcmV3ZWxsLmxpc3Q9cmVhZC5jc3YoIi4uL2RhdGEvZmFyZXdlbGxsaXN0LmNzdiIsIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSkKYGBgCgpXZSBhc3NlbWJsZSBhbGwgc2NyYXBwZWQgc3BlZWNoZXMgaW50byBvbmUgbGlzdC4gTm90ZSBoZXJlIHRoYXQgd2UgZG9uJ3QgaGF2ZSB0aGUgZnVsbCB0ZXh0IHlldCwgb25seSB0aGUgbGlua3MgdG8gZnVsbCB0ZXh0IHRyYW5zY3JpcHRzLiAKCiMgU3RlcCAzOiBzY3JhcCB0aGUgdGV4dHMgb2Ygc3BlZWNoZXMgZnJvbSB0aGUgc3BlZWNoIFVSTHMuCgpgYGB7cn0Kc3BlZWNoLmxpc3Q9cmJpbmQoaW5hdWcubGlzdCwgbm9taW4ubGlzdCwgZmFyZXdlbGwubGlzdCkKc3BlZWNoLmxpc3QkdHlwZT1jKHJlcCgiaW5hdWciLCBucm93KGluYXVnLmxpc3QpKSwKICAgICAgICAgICAgICAgICAgIHJlcCgibm9taW4iLCBucm93KG5vbWluLmxpc3QpKSwKICAgICAgICAgICAgICAgICAgIHJlcCgiZmFyZXdlbGwiLCBucm93KGZhcmV3ZWxsLmxpc3QpKSkKc3BlZWNoLnVybD1yYmluZChpbmF1Zywgbm9taW4sIGZhcmV3ZWxsKQpzcGVlY2gubGlzdD1jYmluZChzcGVlY2gubGlzdCwgc3BlZWNoLnVybCkKYGBgCgpCYXNlZCBvbiB0aGUgbGlzdCBvZiBzcGVlY2hlcywgd2Ugc2NyYXAgdGhlIG1haW4gdGV4dCBwYXJ0IG9mIHRoZSB0cmFuc2NyaXB0J3MgaHRtbCBwYWdlLiBGb3Igc2ltcGxlIGh0bWwgcGFnZXMgb2YgdGhpcyBraW5kLCAgW1NlbGVjdG9yZ2FkZ2V0XShodHRwOi8vc2VsZWN0b3JnYWRnZXQuY29tLykgaXMgdmVyeSBjb252ZW5pZW50IGZvciBpZGVudGlmeWluZyB0aGUgaHRtbCBub2RlIHRoYXQgYHJ2ZXN0YCBjYW4gdXNlIHRvIHNjcmFwIGl0cyBjb250ZW50LiBGb3IgcmVwcm9kdWNpYmlsaXR5LCB3ZSBhbHNvIHNhdmUgb3VyIHNjcmFwcGVkIHNwZWVjaGVzIGludG8gb3VyIGxvY2FsIGZvbGRlciBhcyBpbmRpdmlkdWFsIHNwZWVjaCBmaWxlcy4gCgpgYGB7cn0KIyBMb29wIG92ZXIgZWFjaCByb3cgaW4gc3BlZWNoLmxpc3QKc3BlZWNoLmxpc3QkZnVsbHRleHQ9TkEKZm9yKGkgaW4gc2VxKG5yb3coc3BlZWNoLmxpc3QpKSkgewogIHRleHQgPC0gcmVhZF9odG1sKHNwZWVjaC5saXN0JHVybHNbaV0pICU+JSAjIGxvYWQgdGhlIHBhZ2UKICAgIGh0bWxfbm9kZXMoIi5kaXNwbGF5dGV4dCIpICU+JSAjIGlzbG9hdGUgdGhlIHRleHQKICAgIGh0bWxfdGV4dCgpICMgZ2V0IHRoZSB0ZXh0CiAgc3BlZWNoLmxpc3QkZnVsbHRleHRbaV09dGV4dAogICMgQ3JlYXRlIHRoZSBmaWxlIG5hbWUKICBmaWxlbmFtZSA8LSBwYXN0ZTAoIi4uL2RhdGEvZnVsbHRleHQvIiwgCiAgICAgICAgICAgICAgICAgICAgIHNwZWVjaC5saXN0JHR5cGVbaV0sCiAgICAgICAgICAgICAgICAgICAgIHNwZWVjaC5saXN0JEZpbGVbaV0sICItIiwgCiAgICAgICAgICAgICAgICAgICAgIHNwZWVjaC5saXN0JFRlcm1baV0sICIudHh0IikKICBzaW5rKGZpbGUgPSBmaWxlbmFtZSkgJT4lICMgb3BlbiBmaWxlIHRvIHdyaXRlIAogIGNhdCh0ZXh0KSAgIyB3cml0ZSB0aGUgZmlsZQogIHNpbmsoKSAjIGNsb3NlIHRoZSBmaWxlCn0KYGBgCgpUcnVtcCwgYXMgcHJlc2lkZW50LWVsZWN0IHRoYXQgaGFzIG5vdCBiZWVuIGEgcG9saXRpY2lhbiwgZG8gbm90IGhhdmUgYSBsb3Qgb2YgZm9ybWFsIHNwZWVjaGVzIHlldC4gRm9yIG91ciB0ZXh0dWFsIGFuYWx5c2lzLCB3ZSBtYW51YWxseSBhZGQgc2V2ZXJhbCBwdWJsaWMgdHJhbnNjcmlwdHMgZnJvbSBUcnVtcDoKKyBbVHJhbnNjcmlwdDogRG9uYWxkIFRydW1wJ3MgZnVsbCBpbW1pZ3JhdGlvbiBzcGVlY2gsIGFubm90YXRlZC4gTEEgVGltZXMsIDA4LzMxLzIwMTZdIChodHRwOi8vd3d3LmxhdGltZXMuY29tL3BvbGl0aWNzL2xhLW5hLXBvbC1kb25hbGQtdHJ1bXAtaW1taWdyYXRpb24tc3BlZWNoLXRyYW5zY3JpcHQtMjAxNjA4MzEtc25hcC1odG1sc3RvcnkuaHRtbCkKKyBbVHJhbnNjcmlwdCBvZiBEb25hbGQgVHJ1bXDigJlzIHNwZWVjaCBvbiBuYXRpb25hbCBzZWN1cml0eSBpbiBQaGlsYWRlbHBoaWEKLSBUaGUgSGlsbCwgMDkvMDcvMTZdKGh0dHA6Ly90aGVoaWxsLmNvbS9ibG9ncy9wdW5kaXRzLWJsb2cvY2FtcGFpZ24vMjk0ODE3LXRyYW5zY3JpcHQtb2YtZG9uYWxkLXRydW1wcy1zcGVlY2gtb24tbmF0aW9uYWwtc2VjdXJpdHktaW4pCisgW1RyYW5zY3JpcHQgb2YgUHJlc2lkZW50LWVsZWN0IFRydW1wJ3MgbmV3cyBjb25mZXJlbmNlCkNOQkMsIDAxLzExLzIwMTddKGh0dHA6Ly93d3cuY25iYy5jb20vMjAxNy8wMS8xMS90cmFuc2NyaXB0LW9mLXByZXNpZGVudC1lbGVjdC1kb25hbGQtai10cnVtcHMtbmV3cy1jb25mZXJlbmNlLmh0bWwpCgpgYGB7cn0Kc3BlZWNoMT1wYXN0ZShyZWFkTGluZXMoIi4uL2RhdGEvZnVsbHRleHQvU3BlZWNoRG9uYWxkVHJ1bXAtTkEudHh0IiwgCiAgICAgICAgICAgICAgICAgIG49LTEsIHNraXBOdWw9VFJVRSksCiAgICAgICAgICAgICAgY29sbGFwc2U9IiAiKQpzcGVlY2gyPXBhc3RlKHJlYWRMaW5lcygiLi4vZGF0YS9mdWxsdGV4dC9TcGVlY2hEb25hbGRUcnVtcC1OQTIudHh0IiwgCiAgICAgICAgICAgICAgICAgIG49LTEsIHNraXBOdWw9VFJVRSksCiAgICAgICAgICAgICAgY29sbGFwc2U9IiAiKQpzcGVlY2gzPXBhc3RlKHJlYWRMaW5lcygiLi4vZGF0YS9mdWxsdGV4dC9QcmVzc0RvbmFsZFRydW1wLU5BLnR4dCIsIAogICAgICAgICAgICAgICAgICBuPS0xLCBza2lwTnVsPVRSVUUpLAogICAgICAgICAgICAgIGNvbGxhcHNlPSIgIikKClRydW1wLnNwZWVjaGVzPWRhdGEuZnJhbWUoCiAgUHJlc2lkZW50PXJlcCgiRG9uYWxkIEouIFRydW1wIiwgMyksCiAgRmlsZT1yZXAoIkRvbmFsZEpUcnVtcCIsIDMpLAogIFRlcm09cmVwKDAsIDMpLAogIFBhcnR5PXJlcCgiUmVwdWJsaWNhbiIsIDMpLAogIERhdGU9YygiQXVndXN0IDMxLCAyMDE2IiwgIlNlcHRlbWJlciA3LCAyMDE2IiwgIkphbnVhcnkgMTEsIDIwMTciKSwKICBXb3Jkcz1jKHdvcmRfY291bnQoc3BlZWNoMSksIHdvcmRfY291bnQoc3BlZWNoMiksIHdvcmRfY291bnQoc3BlZWNoMykpLAogIFdpbj1yZXAoInllcyIsIDMpLAogIHR5cGU9cmVwKCJzcGVlY2hlcyIsIDMpLAogIGxpbmtzPXJlcChOQSwgMyksCiAgdXJscz1yZXAoTkEsIDMpLAogIGZ1bGx0ZXh0PWMoc3BlZWNoMSwgc3BlZWNoMiwgc3BlZWNoMykKKQoKc3BlZWNoLmxpc3Q9cmJpbmQoc3BlZWNoLmxpc3QsIFRydW1wLnNwZWVjaGVzKQpgYGAKCiMgU3RlcCA0OiBkYXRhIFByb2Nlc3NpbmcgLS0tIGdlbmVyYXRlIGxpc3Qgb2Ygc2VudGVuY2VzCgpXZSB3aWxsIHVzZSBzZW50ZW5jZXMgYXMgdW5pdHMgb2YgYW5hbHlzaXMgZm9yIHRoaXMgcHJvamVjdCwgYXMgc2VudGVuY2VzIGFyZSBuYXR1cmFsIGxhbmd1Z2UgdW5pdHMgZm9yIG9yZ2FuaXppbmcgdGhvdWdodHMgYW5kIGlkZWFzLiBGb3IgZWFjaCBleHRyYWN0ZWQgc2VudGVuY2UsIHdlIGFwcGx5IHNlbnRpbWVudCBhbmFseXNpcyB1c2luZyBbTlJDIHNlbnRpbWVudCBsZXhpb25dKGh0dHA6Ly9zYWlmbW9oYW1tYWQuY29tL1dlYlBhZ2VzL05SQy1FbW90aW9uLUxleGljb24uaHRtKS4gIlRoZSBOUkMgRW1vdGlvbiBMZXhpY29uIGlzIGEgbGlzdCBvZiBFbmdsaXNoIHdvcmRzIGFuZCB0aGVpciBhc3NvY2lhdGlvbnMgd2l0aCBlaWdodCBiYXNpYyBlbW90aW9ucyAoYW5nZXIsIGZlYXIsIGFudGljaXBhdGlvbiwgdHJ1c3QsIHN1cnByaXNlLCBzYWRuZXNzLCBqb3ksIGFuZCBkaXNndXN0KSBhbmQgdHdvIHNlbnRpbWVudHMgKG5lZ2F0aXZlIGFuZCBwb3NpdGl2ZSkuIFRoZSBhbm5vdGF0aW9ucyB3ZXJlIG1hbnVhbGx5IGRvbmUgYnkgY3Jvd2Rzb3VyY2luZy4iCgpXZSBhc3NpZ24gYW4gc2VxdWVudGlhbCBpZCB0byBlYWNoIHNlbnRlbmNlIGluIGEgc3BlZWNoIChgc2VudC5pZGApIGFuZCBhbHNvIGNhbGN1bGF0ZWQgdGhlIG51bWJlciBvZiB3b3JkcyBpbiBlYWNoIHNlbnRlbmNlIGFzICpzZW50ZW5jZSBsZW5ndGgqIChgd29yZC5jb3VudGApLgoKYGBge3IsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CnNlbnRlbmNlLmxpc3Q9TlVMTApmb3IoaSBpbiAxOm5yb3coc3BlZWNoLmxpc3QpKXsKICBzZW50ZW5jZXM9c2VudF9kZXRlY3Qoc3BlZWNoLmxpc3QkZnVsbHRleHRbaV0sCiAgICAgICAgICAgICAgICAgICAgICAgIGVuZG1hcmtzID0gYygiPyIsICIuIiwgIiEiLCAifCIsIjsiKSkKICBpZihsZW5ndGgoc2VudGVuY2VzKT4wKXsKICAgIGVtb3Rpb25zPWdldF9ucmNfc2VudGltZW50KHNlbnRlbmNlcykKICAgIHdvcmQuY291bnQ9d29yZF9jb3VudChzZW50ZW5jZXMpCiAgICAjIGNvbG5hbWVzKGVtb3Rpb25zKT1wYXN0ZTAoImVtby4iLCBjb2xuYW1lcyhlbW90aW9ucykpCiAgICAjIGluIGNhc2UgdGhlIHdvcmQgY291bnRzIGFyZSB6ZXJvcz8KICAgIGVtb3Rpb25zPWRpYWcoMS8od29yZC5jb3VudCswLjAxKSklKiVhcy5tYXRyaXgoZW1vdGlvbnMpCiAgICBzZW50ZW5jZS5saXN0PXJiaW5kKHNlbnRlbmNlLmxpc3QsIAogICAgICAgICAgICAgICAgICAgICAgICBjYmluZChzcGVlY2gubGlzdFtpLC1uY29sKHNwZWVjaC5saXN0KV0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlbnRlbmNlcz1hcy5jaGFyYWN0ZXIoc2VudGVuY2VzKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdvcmQuY291bnQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVtb3Rpb25zLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZW50LmlkPTE6bGVuZ3RoKHNlbnRlbmNlcykKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKQogICAgKQogIH0KfQpgYGAKClNvbWUgbm9uLXNlbnRlbmNlcyBleGlzdCBpbiByYXcgZGF0YSBkdWUgdG8gZXJyb25lb3VzIGV4dHJhIGVuZC1vZiBzZW50ZW5jZSBtYXJrcy4gCmBgYHtyfQpzZW50ZW5jZS5saXN0PQogIHNlbnRlbmNlLmxpc3QlPiUKICBmaWx0ZXIoIWlzLm5hKHdvcmQuY291bnQpKSAKCmBgYAoKIyBTdGVwIDU6IERhdGEgYW5hbHlzaXMgLS0tIGxlbmd0aCBvZiBzZW50ZW5jZXMKCkZvciBzaW1wbGVyIHZpc3VhbGl6YXRpb24sIHdlIGNob3NlIGEgc3Vic2V0IG9mIGJldHRlciBrbm93biBwcmVzaWRlbnRzIG9yIHByZXNpZGVudGlhbCBjYW5kaWRhdGVzIG9uIHdoaWNoIHRvIGZvY3VzIG91ciBhbmFseXNpcy4gCgpgYGB7cn0Kc2VsLmNvbXBhcmlzb249YygiRG9uYWxkSlRydW1wIiwiSm9obk1jQ2FpbiIsICJHZW9yZ2VCdXNoIiwgIk1pdHRSb21uZXkiLCAiR2VvcmdlV0J1c2giLAogICAgICAgICAgICAgICAgICJSb25hbGRSZWFnYW4iLCJBbGJlcnRHb3JlLEpyIiwgIkhpbGxhcnlDbGludG9uIiwiSm9obkZLZXJyeSIsIAogICAgICAgICAgICAgICAgICJXaWxsaWFtSkNsaW50b24iLCJIYXJyeVNUcnVtYW4iLCAiQmFyYWNrT2JhbWEiLCAiTHluZG9uQkpvaG5zb24iLAogICAgICAgICAgICAgICAgICJHZXJhbGRSRm9yZCIsICJKaW1teUNhcnRlciIsICJEd2lnaHRERWlzZW5ob3dlciIsICJGcmFua2xpbkRSb29zZXZlbHQiLAogICAgICAgICAgICAgICAgICJIZXJiZXJ0SG9vdmVyIiwiSm9obkZLZW5uZWR5IiwiUmljaGFyZE5peG9uIiwiV29vZHJvd1dpbHNvbiIsIAogICAgICAgICAgICAgICAgICJBYnJhaGFtTGluY29sbiIsICJUaGVvZG9yZVJvb3NldmVsdCIsICJKYW1lc0dhcmZpZWxkIiwgCiAgICAgICAgICAgICAgICAgIkpvaG5RdWluY3lBZGFtcyIsICJVbHlzc2VzU0dyYW50IiwgIlRob21hc0plZmZlcnNvbiIsCiAgICAgICAgICAgICAgICAgIkdlb3JnZVdhc2hpbmd0b24iLCAiV2lsbGlhbUhvd2FyZFRhZnQiLCAiQW5kcmV3SmFja3NvbiIsCiAgICAgICAgICAgICAgICAgIldpbGxpYW1IZW5yeUhhcnJpc29uIiwgIkpvaG5BZGFtcyIpCmBgYAoKIyMgT3ZlcnZpZXcgb2Ygc2VudGVuY2UgbGVuZ3RoIGRpc3RyaWJ1dGlvbiBieSBkaWZmZXJlbnQgdHlwZXMgb2Ygc3BlZWNoZXMuIAoKIyMjIE5vbWluYXRpb24gc3BlZWNoZXMgCgpGaXJzdCwgd2UgbG9vayBhdCAqbm9taW5hdGlvbiBhY2NlcHRhbmNlIHNwZWVjaGVzKiBhdCBtYWpvciBwYXJ0eSdzIG5hdGlvbmFsIGNvbnZlbnRpb25zLiBGb3IgcmVsZXZhbnQgdG8gVHJ1bXAncyBzcGVlY2hlcywgd2UgbGltaXQgb3VyIGF0dGVudGlvbiB0byBzcGVlY2hlcyBmb3IgdGhlIGZpcnN0IHRlcm1zIG9mIGZvcm1lciBVLlMuIHByZXNpZGVudHMuICBXZSBub3RpY2VkIHRoYXQgYSBudW1iZXIgb2YgcHJlc2lkZW50cyBoYXZlIHZlcnkgc2hvcnQgc2VudGVuY2VzIGluIHRoZWlyIG5vbWluYXRpb24gYWNjZXB0YW5jZSBzcGVlY2hlcy4gCgojIyMjIEZpcnN0IHRlcm0KCmBgYHtyLCBmaWcud2lkdGggPSAzLCBmaWcuaGVpZ2h0ID0gM30KCnBhcihtYXI9Yyg0LCAxMSwgMiwgMikpCgojc2VsLmNvbXBhcmlzb249bGV2ZWxzKHNlbnRlbmNlLmxpc3QkRmlsZU9yZGVyZWQpCnNlbnRlbmNlLmxpc3Quc2VsPWZpbHRlcihzZW50ZW5jZS5saXN0LCAKICAgICAgICAgICAgICAgICAgICAgICAgdHlwZT09Im5vbWluIiwgVGVybT09MSwgRmlsZSVpbiVzZWwuY29tcGFyaXNvbikKc2VudGVuY2UubGlzdC5zZWwkRmlsZT1mYWN0b3Ioc2VudGVuY2UubGlzdC5zZWwkRmlsZSkKCnNlbnRlbmNlLmxpc3Quc2VsJEZpbGVPcmRlcmVkPXJlb3JkZXIoc2VudGVuY2UubGlzdC5zZWwkRmlsZSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZW50ZW5jZS5saXN0LnNlbCR3b3JkLmNvdW50LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1lYW4sIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb3JkZXI9VCkKCmJlZXN3YXJtKHdvcmQuY291bnR+RmlsZU9yZGVyZWQsIAogICAgICAgICBkYXRhPXNlbnRlbmNlLmxpc3Quc2VsLAogICAgICAgICBob3Jpem9udGFsID0gVFJVRSwgCiAgICAgICAgIHBjaD0xNiwgY29sPWFscGhhKGJyZXdlci5wYWwoOSwgIlNldDEiKSwgMC42KSwgCiAgICAgICAgIGNleD0wLjU1LCBjZXguYXhpcz0wLjgsIGNleC5sYWI9MC44LAogICAgICAgICBzcGFjaW5nPTUvbmxldmVscyhzZW50ZW5jZS5saXN0LnNlbCRGaWxlT3JkZXJlZCksCiAgICAgICAgIGxhcz0yLCB4bGFiPSJOdW1iZXIgb2Ygd29yZHMgaW4gYSBzZW50ZW5jZS4iLCB5bGFiPSIiLAogICAgICAgICBtYWluPSJOb21pbmF0aW9uIHNwZWVjaGVzIikKCmBgYAoKIyMjIyBTZWNvbmQgdGVybQoKYGBge3IsIGZpZy53aWR0aCA9IDMsIGZpZy5oZWlnaHQgPSAxLjN9CgpwYXIobWFyPWMoNCwgMTEsIDIsIDIpKQoKI3NlbC5jb21wYXJpc29uPWxldmVscyhzZW50ZW5jZS5saXN0JEZpbGVPcmRlcmVkKQpzZW50ZW5jZS5saXN0LnNlbD1maWx0ZXIoc2VudGVuY2UubGlzdCwgCiAgICAgICAgICAgICAgICAgICAgICAgIHR5cGU9PSJub21pbiIsIFRlcm09PTIsIEZpbGUlaW4lc2VsLmNvbXBhcmlzb24pCnNlbnRlbmNlLmxpc3Quc2VsJEZpbGU9ZmFjdG9yKHNlbnRlbmNlLmxpc3Quc2VsJEZpbGUpCgpzZW50ZW5jZS5saXN0LnNlbCRGaWxlT3JkZXJlZD1yZW9yZGVyKHNlbnRlbmNlLmxpc3Quc2VsJEZpbGUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VudGVuY2UubGlzdC5zZWwkd29yZC5jb3VudCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtZWFuLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9yZGVyPVQpCgpiZWVzd2FybSh3b3JkLmNvdW50fkZpbGVPcmRlcmVkLCAKICAgICAgICAgZGF0YT1zZW50ZW5jZS5saXN0LnNlbCwKICAgICAgICAgaG9yaXpvbnRhbCA9IFRSVUUsIAogICAgICAgICBwY2g9MTYsIGNvbD1hbHBoYShicmV3ZXIucGFsKDksICJTZXQxIiksIDAuNiksIAogICAgICAgICBjZXg9MC41NSwgY2V4LmF4aXM9MC44LCBjZXgubGFiPTAuOCwKICAgICAgICAgc3BhY2luZz0xLjIvbmxldmVscyhzZW50ZW5jZS5saXN0LnNlbCRGaWxlT3JkZXJlZCksCiAgICAgICAgIGxhcz0yLCB4bGFiPSJOdW1iZXIgb2Ygd29yZHMgaW4gYSBzZW50ZW5jZS4iLCB5bGFiPSIiLAogICAgICAgICBtYWluPSJOb21pbmF0aW9uIHNwZWVjaGVzLCAybmQgdGVybSIpCgpgYGAKCldoYXQgYXJlIHRoZXNlIHNob3J0IHNlbnRlbmNlcz8KYGBge3J9CnNlbnRlbmNlLmxpc3QlPiUKICBmaWx0ZXIoRmlsZT09IkRvbmFsZEpUcnVtcCIsIAogICAgICAgICB0eXBlPT0ibm9taW4iLCAKICAgICAgICAgd29yZC5jb3VudDw9MyklPiUKICBzZWxlY3Qoc2VudGVuY2VzKSU+JXNhbXBsZV9uKDEwKQoKc2VudGVuY2UubGlzdCU+JQogIGZpbHRlcihGaWxlPT0iQWxiZXJ0R29yZSxKciIsIAogICAgICAgICB0eXBlPT0ibm9taW4iLCAKICAgICAgICAgd29yZC5jb3VudDw9MyklPiUKICBzZWxlY3Qoc2VudGVuY2VzKSU+JXNhbXBsZV9uKDEwKQoKc2VudGVuY2UubGlzdCU+JQogIGZpbHRlcihGaWxlPT0iQ2xpbnRvbiIsIAogICAgICAgICB0eXBlPT0ibm9taW4iLCAKICAgICAgICAgd29yZC5jb3VudDw9MyklPiUKICBzZWxlY3Qoc2VudGVuY2VzKQoKc2VudGVuY2UubGlzdCU+JQogIGZpbHRlcihGaWxlPT0iV2lsbGlhbUpDbGludG9uIiwgCiAgICAgICAgIHR5cGU9PSJub21pbiIsIFRlcm09PTEsCiAgICAgICAgIHdvcmQuY291bnQ8PTMpJT4lCiAgc2VsZWN0KHNlbnRlbmNlcykKYGBgCgoKIyMjIEluYXVndXJhbCBzcGVlY2hlcwoKV2Ugbm90aWNlIHRoYXQgdGhlIHNlbnRlbmNlcyBpbiBpbmF1Z3VyYWwgc3BlZWNoZXMgYXJlIGxvbmdlciB0aGFuIHRob3NlIGluIG5vbWluYXRpb24gYWNjZXB0YW5jZSBzcGVlY2hlcy4gCgpgYGB7ciwgZmlnLndpZHRoID0gMywgZmlnLmhlaWdodCA9IDN9CnNlbnRlbmNlLmxpc3Quc2VsPXNlbnRlbmNlLmxpc3QlPiVmaWx0ZXIodHlwZT09ImluYXVnIiwgRmlsZSVpbiVzZWwuY29tcGFyaXNvbiwgVGVybT09MSkKc2VudGVuY2UubGlzdC5zZWwkRmlsZT1mYWN0b3Ioc2VudGVuY2UubGlzdC5zZWwkRmlsZSkKCnNlbnRlbmNlLmxpc3Quc2VsJEZpbGVPcmRlcmVkPXJlb3JkZXIoc2VudGVuY2UubGlzdC5zZWwkRmlsZSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZW50ZW5jZS5saXN0LnNlbCR3b3JkLmNvdW50LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1lYW4sIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb3JkZXI9VCkKcGFyKG1hcj1jKDQsIDExLCAyLCAyKSkKCmJlZXN3YXJtKHdvcmQuY291bnR+RmlsZU9yZGVyZWQsIAogICAgICAgICBkYXRhPXNlbnRlbmNlLmxpc3Quc2VsLAogICAgICAgICBob3Jpem9udGFsID0gVFJVRSwKICAgICAgICAgcGNoPTE2LCBjb2w9YWxwaGEoYnJld2VyLnBhbCg5LCAiU2V0MSIpLCAwLjYpLCAKICAgICAgICAgY2V4PTAuNTUsIGNleC5heGlzPTAuOCwgY2V4LmxhYj0wLjgsCiAgICAgICAgIHNwYWNpbmc9NS9ubGV2ZWxzKHNlbnRlbmNlLmxpc3Quc2VsJEZpbGVPcmRlcmVkKSwKICAgICAgICAgbGFzPTIsIHlsYWI9IiIsIHhsYWI9Ik51bWJlciBvZiB3b3JkcyBpbiBhIHNlbnRlbmNlLiIsCiAgICAgICAgIG1haW49IkluYXVndXJhbCBTcGVlY2hlcyIpCmBgYAoKU2hvcnQgc2VudGVuY2VzIGluIGluYXVndXJhbCBzcGVlY2hlcy4gCmBgYHtyfQpzZW50ZW5jZS5saXN0JT4lCiAgZmlsdGVyKEZpbGU9PSJCYXJhY2tPYmFtYSIsIAogICAgICAgICB0eXBlPT0iaW5hdWciLCAKICAgICAgICAgd29yZC5jb3VudDw9MyklPiUKICBzZWxlY3Qoc2VudGVuY2VzKQpgYGAKCgojIFN0ZXAgNTogRGF0YSBhbmFseXNpcyAtLS0gc2VudGltZW50IGFuYWxzaXMKCiMjIFNlbnRlbmNlIGxlbmd0aCB2YXJpYXRpb24gb3ZlciB0aGUgY291cnNlIG9mIHRoZSBzcGVlY2gsIHdpdGggZW1vdGlvbnMuIAoKSG93IG91ciBwcmVzaWRlbnRzIChvciBjYW5kaWRhdGVzKSBhbHRlcm5hdGUgYmV0d2VlbiBsb25nIGFuZCBzaG9ydCBzZW50ZW5jZXMgYW5kIGhvdyB0aGV5IHNoaWZ0IGJldHdlZW4gZGlmZmVyZW50IHNlbnRpbWVudHMgaW4gdGhlaXIgc3BlZWNoZXMuIEl0IGlzIGludGVyZXN0aW5nIHRvIG5vdGUgdGhhdCBzb21lIHByZXNpZGVudGlhbCBjYW5kaWRhdGVzJyBzcGVlY2ggYXJlIG1vcmUgY29sb3JmdWwgdGhhbiBvdGhlcnMuIEhlcmUgd2UgdXNlZCB0aGUgc2FtZSBjb2xvciB0aGVtZSBhcyBpbiB0aGUgbW92aWUgIkluc2lkZSBPdXQuIgoKIVtpbWFnZV0oaHR0cDovL3d3dy5zdGFmZm9yZHNjaG9vbHMubmV0L2Ntcy9saWIwMTEvVkEwMTgxODcyMy9DZW50cmljaXR5L0RvbWFpbi8zNTc0L2NoYXJhY3Rlcl9pY29uLnBuZykKCmBgYHtyLCBmaWcuaGVpZ2h0PTIuNSwgZmlnLndpZHRoPTJ9CnBhcihtZnJvdz1jKDQsMSksIG1hcj1jKDEsMCwyLDApLCBidHk9Im4iLCB4YXh0PSJuIiwgeWF4dD0ibiIsIGZvbnQubWFpbj0xKQoKZi5wbG90c2VudC5sZW4oSW4ubGlzdD1zZW50ZW5jZS5saXN0LCBJbkZpbGU9IkhpbGxhcnlDbGludG9uIiwgCiAgICAgICAgICAgICAgIEluVHlwZT0ibm9taW4iLCBJblRlcm09MSwgUHJlc2lkZW50PSJIaWxsYXJ5IENsaW50b24iKQoKZi5wbG90c2VudC5sZW4oSW4ubGlzdD1zZW50ZW5jZS5saXN0LCBJbkZpbGU9IkRvbmFsZEpUcnVtcCIsIAogICAgICAgICAgICAgICBJblR5cGU9Im5vbWluIiwgSW5UZXJtPTEsIFByZXNpZGVudD0iRG9uYWxkIFRydW1wIikKCmYucGxvdHNlbnQubGVuKEluLmxpc3Q9c2VudGVuY2UubGlzdCwgSW5GaWxlPSJCYXJhY2tPYmFtYSIsIAogICAgICAgICAgICAgICBJblR5cGU9Im5vbWluIiwgSW5UZXJtPTEsIFByZXNpZGVudD0iQmFyYWNrIE9iYW1hIikKCmYucGxvdHNlbnQubGVuKEluLmxpc3Q9c2VudGVuY2UubGlzdCwgSW5GaWxlPSJHZW9yZ2VXQnVzaCIsIAogICAgICAgICAgICAgICBJblR5cGU9Im5vbWluIiwgSW5UZXJtPTEsIFByZXNpZGVudD0iR2VvcmdlIFcuIEJ1c2giKQpgYGAKCiMjIyBXaGF0IGFyZSB0aGUgZW1vdGlvbmFsbHkgY2hhcmdlZCBzZW50ZW5jZXM/CgpgYGB7cn0KcHJpbnQoIkhpbGxhcnkgQ2xpbnRvbiIpCnNwZWVjaC5kZj10YmxfZGYoc2VudGVuY2UubGlzdCklPiUKICBmaWx0ZXIoRmlsZT09IkhpbGxhcnlDbGludG9uIiwgdHlwZT09Im5vbWluIiwgd29yZC5jb3VudD49NCklPiUKICBzZWxlY3Qoc2VudGVuY2VzLCBhbmdlcjp0cnVzdCkKc3BlZWNoLmRmPWFzLmRhdGEuZnJhbWUoc3BlZWNoLmRmKQphcy5jaGFyYWN0ZXIoc3BlZWNoLmRmJHNlbnRlbmNlc1thcHBseShzcGVlY2guZGZbLC0xXSwgMiwgd2hpY2gubWF4KV0pCgpwcmludCgiQmFyYWNrIE9iYW1hIikKc3BlZWNoLmRmPXRibF9kZihzZW50ZW5jZS5saXN0KSU+JQogIGZpbHRlcihGaWxlPT0iQmFyYWNrT2JhbWEiLCB0eXBlPT0ibm9taW4iLCBUZXJtPT0xLCB3b3JkLmNvdW50Pj01KSU+JQogIHNlbGVjdChzZW50ZW5jZXMsIGFuZ2VyOnRydXN0KQpzcGVlY2guZGY9YXMuZGF0YS5mcmFtZShzcGVlY2guZGYpCmFzLmNoYXJhY3RlcihzcGVlY2guZGYkc2VudGVuY2VzW2FwcGx5KHNwZWVjaC5kZlssLTFdLCAyLCB3aGljaC5tYXgpXSkKCnByaW50KCJHZW9yZ2UgVyBCdXNoIikKc3BlZWNoLmRmPXRibF9kZihzZW50ZW5jZS5saXN0KSU+JQogIGZpbHRlcihGaWxlPT0iR2VvcmdlV0J1c2giLCB0eXBlPT0ibm9taW4iLCBUZXJtPT0xLCB3b3JkLmNvdW50Pj00KSU+JQogIHNlbGVjdChzZW50ZW5jZXMsIGFuZ2VyOnRydXN0KQpzcGVlY2guZGY9YXMuZGF0YS5mcmFtZShzcGVlY2guZGYpCmFzLmNoYXJhY3RlcihzcGVlY2guZGYkc2VudGVuY2VzW2FwcGx5KHNwZWVjaC5kZlssLTFdLCAyLCB3aGljaC5tYXgpXSkKCnByaW50KCJEb25hbGQgVHJ1bXAiKQpzcGVlY2guZGY9dGJsX2RmKHNlbnRlbmNlLmxpc3QpJT4lCiAgZmlsdGVyKEZpbGU9PSJEb25hbGRKVHJ1bXAiLCB0eXBlPT0ibm9taW4iLCBUZXJtPT0xLCB3b3JkLmNvdW50Pj01KSU+JQogIHNlbGVjdChzZW50ZW5jZXMsIGFuZ2VyOnRydXN0KQpzcGVlY2guZGY9YXMuZGF0YS5mcmFtZShzcGVlY2guZGYpCmFzLmNoYXJhY3RlcihzcGVlY2guZGYkc2VudGVuY2VzW2FwcGx5KHNwZWVjaC5kZlssLTFdLCAyLCB3aGljaC5tYXgpXSkKCmBgYAoKCiMjIENsdXN0ZXJpbmcgb2YgZW1vdGlvbnMKYGBge3IsIGZpZy53aWR0aD0yLCBmaWcuaGVpZ2h0PTJ9CmhlYXRtYXAuMihjb3Ioc2VudGVuY2UubGlzdCU+JWZpbHRlcih0eXBlPT0iaW5hdWciKSU+JXNlbGVjdChhbmdlcjp0cnVzdCkpLCAKICAgICAgICAgIHNjYWxlID0gIm5vbmUiLCAKICAgICAgICAgIGNvbCA9IGJsdWVyZWQoMTAwKSwgLCBtYXJnaW49Yyg2LCA2KSwga2V5PUYsCiAgICAgICAgICB0cmFjZSA9ICJub25lIiwgZGVuc2l0eS5pbmZvID0gIm5vbmUiKQoKcGFyKG1hcj1jKDQsIDYsIDIsIDEpKQplbW8ubWVhbnM9Y29sTWVhbnMoc2VsZWN0KHNlbnRlbmNlLmxpc3QsIGFuZ2VyOnRydXN0KT4wLjAxKQpjb2wudXNlPWMoInJlZDIiLCAiZGFya2dvbGRlbnJvZDEiLCAKICAgICAgICAgICAgImNoYXJ0cmV1c2UzIiwgImJsdWV2aW9sZXQiLAogICAgICAgICAgICAiZGFya2dvbGRlbnJvZDIiLCAiZG9kZ2VyYmx1ZTMiLCAKICAgICAgICAgICAgImRhcmtnb2xkZW5yb2QxIiwgImRhcmtnb2xkZW5yb2QxIikKYmFycGxvdChlbW8ubWVhbnNbb3JkZXIoZW1vLm1lYW5zKV0sIGxhcz0yLCBjb2w9Y29sLnVzZVtvcmRlcihlbW8ubWVhbnMpXSwgaG9yaXo9VCwgbWFpbj0iSW5hdWd1cmFsIFNwZWVjaGVzIikKYGBgCgpgYGB7ciwgZmlnLmhlaWdodD0zLjMsIGZpZy53aWR0aD0zLjd9CnByZXNpZC5zdW1tYXJ5PXRibF9kZihzZW50ZW5jZS5saXN0KSU+JQogIGZpbHRlcih0eXBlPT0ibm9taW4iLCBGaWxlJWluJXNlbC5jb21wYXJpc29uKSU+JQogICNncm91cF9ieShwYXN0ZTAodHlwZSwgRmlsZSkpJT4lCiAgZ3JvdXBfYnkoRmlsZSklPiUKICBzdW1tYXJpc2UoCiAgICBhbmdlcj1tZWFuKGFuZ2VyKSwKICAgIGFudGljaXBhdGlvbj1tZWFuKGFudGljaXBhdGlvbiksCiAgICBkaXNndXN0PW1lYW4oZGlzZ3VzdCksCiAgICBmZWFyPW1lYW4oZmVhciksCiAgICBqb3k9bWVhbihqb3kpLAogICAgc2FkbmVzcz1tZWFuKHNhZG5lc3MpLAogICAgc3VycHJpc2U9bWVhbihzdXJwcmlzZSksCiAgICB0cnVzdD1tZWFuKHRydXN0KQogICAgI25lZ2F0aXZlPW1lYW4obmVnYXRpdmUpLAogICAgI3Bvc2l0aXZlPW1lYW4ocG9zaXRpdmUpCiAgKQoKcHJlc2lkLnN1bW1hcnk9YXMuZGF0YS5mcmFtZShwcmVzaWQuc3VtbWFyeSkKcm93bmFtZXMocHJlc2lkLnN1bW1hcnkpPWFzLmNoYXJhY3RlcigocHJlc2lkLnN1bW1hcnlbLDFdKSkKa20ucmVzPWttZWFucyhwcmVzaWQuc3VtbWFyeVssLTFdLCBpdGVyLm1heD0yMDAsCiAgICAgICAgICAgICAgNSkKZnZpel9jbHVzdGVyKGttLnJlcywgCiAgICAgICAgICAgICBzdGFuZD1GLCByZXBlbD0gVFJVRSwKICAgICAgICAgICAgIGRhdGEgPSBwcmVzaWQuc3VtbWFyeVssLTFdLCB4bGFiPSIiLCB4YXh0PSJuIiwKICAgICAgICAgICAgIHNob3cuY2x1c3QuY2VudD1GQUxTRSkKYGBgCgojIFN0ZXAgNTogRGF0YSBhbmFseXNpcyAtLS0gVG9waWMgbW9kZWxpbmcKCkZvciB0b3BpYyBtb2RlbGluZywgd2UgcHJlcGFyZSBhIGNvcnB1cyBvZiBzZW50ZW5jZSBzbmlwZXRzIGFzIGZvbGxvd3MuIEZvciBlYWNoIHNwZWVjaCwgd2Ugc3RhcnQgd2l0aCBzZW50ZW5jZXMgYW5kIHByZXBhcmUgYSBzbmlwZXQgd2l0aCBhIGdpdmVuIHNlbnRlbmNlIHdpdGggdGhlIGZsYW5raW5nIHNlbnRlbmNlcy4gCgpgYGB7cn0KY29ycHVzLmxpc3Q9c2VudGVuY2UubGlzdFsyOihucm93KHNlbnRlbmNlLmxpc3QpLTEpLCBdCnNlbnRlbmNlLnByZT1zZW50ZW5jZS5saXN0JHNlbnRlbmNlc1sxOihucm93KHNlbnRlbmNlLmxpc3QpLTIpXQpzZW50ZW5jZS5wb3N0PXNlbnRlbmNlLmxpc3Qkc2VudGVuY2VzWzM6KG5yb3coc2VudGVuY2UubGlzdCktMSldCmNvcnB1cy5saXN0JHNuaXBldHM9cGFzdGUoc2VudGVuY2UucHJlLCBjb3JwdXMubGlzdCRzZW50ZW5jZXMsIHNlbnRlbmNlLnBvc3QsIHNlcD0iICIpCnJtLnJvd3M9KDE6bnJvdyhjb3JwdXMubGlzdCkpW2NvcnB1cy5saXN0JHNlbnQuaWQ9PTFdCnJtLnJvd3M9YyhybS5yb3dzLCBybS5yb3dzLTEpCmNvcnB1cy5saXN0PWNvcnB1cy5saXN0Wy1ybS5yb3dzLCBdCmBgYAoKIyMgVGV4dCBtaW5pbmcKYGBge3J9CmRvY3MgPC0gQ29ycHVzKFZlY3RvclNvdXJjZShjb3JwdXMubGlzdCRzbmlwZXRzKSkKd3JpdGVMaW5lcyhhcy5jaGFyYWN0ZXIoZG9jc1tbc2FtcGxlKDE6bnJvdyhjb3JwdXMubGlzdCksIDEpXV0pKQpgYGAKCiMjIyBUZXh0IGJhc2ljIHByb2Nlc3NpbmcKQWRhcHRlZCBmcm9tIDxodHRwczovL2VpZ2h0MmxhdGUud29yZHByZXNzLmNvbS8yMDE1LzA5LzI5L2EtZ2VudGxlLWludHJvZHVjdGlvbi10by10b3BpYy1tb2RlbGluZy11c2luZy1yLz4uCgpgYGB7cn0KI3JlbW92ZSBwb3RlbnRpYWxseSBwcm9ibGVtYXRpYyBzeW1ib2xzCmRvY3MgPC10bV9tYXAoZG9jcyxjb250ZW50X3RyYW5zZm9ybWVyKHRvbG93ZXIpKQp3cml0ZUxpbmVzKGFzLmNoYXJhY3Rlcihkb2NzW1tzYW1wbGUoMTpucm93KGNvcnB1cy5saXN0KSwgMSldXSkpCgojcmVtb3ZlIHB1bmN0dWF0aW9uCmRvY3MgPC0gdG1fbWFwKGRvY3MsIHJlbW92ZVB1bmN0dWF0aW9uKQp3cml0ZUxpbmVzKGFzLmNoYXJhY3Rlcihkb2NzW1tzYW1wbGUoMTpucm93KGNvcnB1cy5saXN0KSwgMSldXSkpCgojU3RyaXAgZGlnaXRzCmRvY3MgPC0gdG1fbWFwKGRvY3MsIHJlbW92ZU51bWJlcnMpCndyaXRlTGluZXMoYXMuY2hhcmFjdGVyKGRvY3NbW3NhbXBsZSgxOm5yb3coY29ycHVzLmxpc3QpLCAxKV1dKSkKCiNyZW1vdmUgc3RvcHdvcmRzCmRvY3MgPC0gdG1fbWFwKGRvY3MsIHJlbW92ZVdvcmRzLCBzdG9wd29yZHMoImVuZ2xpc2giKSkKd3JpdGVMaW5lcyhhcy5jaGFyYWN0ZXIoZG9jc1tbc2FtcGxlKDE6bnJvdyhjb3JwdXMubGlzdCksIDEpXV0pKQoKI3JlbW92ZSB3aGl0ZXNwYWNlCmRvY3MgPC0gdG1fbWFwKGRvY3MsIHN0cmlwV2hpdGVzcGFjZSkKd3JpdGVMaW5lcyhhcy5jaGFyYWN0ZXIoZG9jc1tbc2FtcGxlKDE6bnJvdyhjb3JwdXMubGlzdCksIDEpXV0pKQoKI1N0ZW0gZG9jdW1lbnQKZG9jcyA8LSB0bV9tYXAoZG9jcyxzdGVtRG9jdW1lbnQpCndyaXRlTGluZXMoYXMuY2hhcmFjdGVyKGRvY3NbW3NhbXBsZSgxOm5yb3coY29ycHVzLmxpc3QpLCAxKV1dKSkKYGBgCgojIyMgVG9waWMgbW9kZWxpbmcKCkdlbmdlcmF0ZSBkb2N1bWVudC10ZXJtIG1hdHJpY2VzLiAKCmBgYHtyfQpkdG0gPC0gRG9jdW1lbnRUZXJtTWF0cml4KGRvY3MpCiNjb252ZXJ0IHJvd25hbWVzIHRvIGZpbGVuYW1lcyNjb252ZXJ0IHJvd25hbWVzIHRvIGZpbGVuYW1lcwpyb3duYW1lcyhkdG0pIDwtIHBhc3RlKGNvcnB1cy5saXN0JHR5cGUsIGNvcnB1cy5saXN0JEZpbGUsCiAgICAgICAgICAgICAgICAgICAgICAgY29ycHVzLmxpc3QkVGVybSwgY29ycHVzLmxpc3Qkc2VudC5pZCwgc2VwPSJfIikKCnJvd1RvdGFscyA8LSBhcHBseShkdG0gLCAxLCBzdW0pICNGaW5kIHRoZSBzdW0gb2Ygd29yZHMgaW4gZWFjaCBEb2N1bWVudAoKZHRtICA8LSBkdG1bcm93VG90YWxzPiAwLCBdCmNvcnB1cy5saXN0PWNvcnB1cy5saXN0W3Jvd1RvdGFscz4wLCBdCgpgYGAKClJ1biBMREEKCmBgYHtyfQojU2V0IHBhcmFtZXRlcnMgZm9yIEdpYmJzIHNhbXBsaW5nCmJ1cm5pbiA8LSA0MDAwCml0ZXIgPC0gMjAwMAp0aGluIDwtIDUwMApzZWVkIDwtbGlzdCgyMDAzLDUsNjMsMTAwMDAxLDc2NSkKbnN0YXJ0IDwtIDUKYmVzdCA8LSBUUlVFCgojTnVtYmVyIG9mIHRvcGljcwprIDwtIDE1CgojUnVuIExEQSB1c2luZyBHaWJicyBzYW1wbGluZwpsZGFPdXQgPC1MREEoZHRtLCBrLCBtZXRob2Q9IkdpYmJzIiwgY29udHJvbD1saXN0KG5zdGFydD1uc3RhcnQsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VlZCA9IHNlZWQsIGJlc3Q9YmVzdCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJ1cm5pbiA9IGJ1cm5pbiwgaXRlciA9IGl0ZXIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhpbj10aGluKSkKI3dyaXRlIG91dCByZXN1bHRzCiNkb2NzIHRvIHRvcGljcwpsZGFPdXQudG9waWNzIDwtIGFzLm1hdHJpeCh0b3BpY3MobGRhT3V0KSkKdGFibGUoYygxOmssIGxkYU91dC50b3BpY3MpKQp3cml0ZS5jc3YobGRhT3V0LnRvcGljcyxmaWxlPXBhc3RlKCIuLi9vdXQvTERBR2liYnMiLGssIkRvY3NUb1RvcGljcy5jc3YiKSkKCiN0b3AgNiB0ZXJtcyBpbiBlYWNoIHRvcGljCmxkYU91dC50ZXJtcyA8LSBhcy5tYXRyaXgodGVybXMobGRhT3V0LDIwKSkKd3JpdGUuY3N2KGxkYU91dC50ZXJtcyxmaWxlPXBhc3RlKCIuLi9vdXQvTERBR2liYnMiLGssIlRvcGljc1RvVGVybXMuY3N2IikpCgojcHJvYmFiaWxpdGllcyBhc3NvY2lhdGVkIHdpdGggZWFjaCB0b3BpYyBhc3NpZ25tZW50CnRvcGljUHJvYmFiaWxpdGllcyA8LSBhcy5kYXRhLmZyYW1lKGxkYU91dEBnYW1tYSkKd3JpdGUuY3N2KHRvcGljUHJvYmFiaWxpdGllcyxmaWxlPXBhc3RlKCIuLi9vdXQvTERBR2liYnMiLGssIlRvcGljUHJvYmFiaWxpdGllcy5jc3YiKSkKYGBgCmBgYHtyfQp0ZXJtcy5iZXRhPWxkYU91dEBiZXRhCnRlcm1zLmJldGE9c2NhbGUodGVybXMuYmV0YSkKdG9waWNzLnRlcm1zPU5VTEwKZm9yKGkgaW4gMTprKXsKICB0b3BpY3MudGVybXM9cmJpbmQodG9waWNzLnRlcm1zLCBsZGFPdXRAdGVybXNbb3JkZXIodGVybXMuYmV0YVtpLF0sIGRlY3JlYXNpbmcgPSBUUlVFKVsxOjddXSkKfQp0b3BpY3MudGVybXMKbGRhT3V0LnRlcm1zCmBgYAoKQmFzZWQgb24gdGhlIG1vc3QgcG9wdWxhciB0ZXJtcyBhbmQgdGhlIG1vc3Qgc2FsaWVudCB0ZXJtcyBmb3IgZWFjaCB0b3BpYywgd2UgYXNzaWduIGEgaGFzaHRhZyB0byBlYWNoIHRvcGljLiBUaGlzIHBhcnQgcmVxdWlyZSBtYW51YWwgc2V0dXAgYXMgdGhlIHRvcGljcyBhcmUgbGlrZWx5IHRvIGNoYW5nZS4gCgpgYGB7cn0KdG9waWNzLmhhc2g9YygiRWNvbm9teSIsICJBbWVyaWNhIiwgIkRlZmVuc2UiLCAiQmVsaWVmIiwgIkVsZWN0aW9uIiwgIlBhdHJpb3Rpc20iLCAiVW5pdHkiLCAiR292ZXJubWVudCIsICJSZWZvcm0iLCAiVGVtcG9yYWwiLCAiV29ya2luZ0ZhbWlsaWVzIiwgIkZyZWVkb20iLCAiRXF1YWxpdHkiLCAiTWlzYyIsICJMZWdpc2xhdGlvbiIpCmNvcnB1cy5saXN0JGxkYXRvcGljPWFzLnZlY3RvcihsZGFPdXQudG9waWNzKQpjb3JwdXMubGlzdCRsZGFoYXNoPXRvcGljcy5oYXNoW2xkYU91dC50b3BpY3NdCgpjb2xuYW1lcyh0b3BpY1Byb2JhYmlsaXRpZXMpPXRvcGljcy5oYXNoCmNvcnB1cy5saXN0LmRmPWNiaW5kKGNvcnB1cy5saXN0LCB0b3BpY1Byb2JhYmlsaXRpZXMpCmBgYAoKIyMgQ2x1c3RlcmluZyBvZiB0b3BpY3MKYGBge3IsIGZpZy53aWR0aD0zLCBmaWcuaGVpZ2h0PTR9CnBhcihtYXI9YygxLDEsMSwxKSkKdG9waWMuc3VtbWFyeT10YmxfZGYoY29ycHVzLmxpc3QuZGYpJT4lCiAgICAgICAgICAgICAgZmlsdGVyKHR5cGUlaW4lYygibm9taW4iLCAiaW5hdWciKSwgRmlsZSVpbiVzZWwuY29tcGFyaXNvbiklPiUKICAgICAgICAgICAgICBzZWxlY3QoRmlsZSwgRWNvbm9teTpMZWdpc2xhdGlvbiklPiUKICAgICAgICAgICAgICBncm91cF9ieShGaWxlKSU+JQogICAgICAgICAgICAgIHN1bW1hcmlzZV9lYWNoKGZ1bnMobWVhbikpCnRvcGljLnN1bW1hcnk9YXMuZGF0YS5mcmFtZSh0b3BpYy5zdW1tYXJ5KQpyb3duYW1lcyh0b3BpYy5zdW1tYXJ5KT10b3BpYy5zdW1tYXJ5WywxXQoKIyBbMV0gIkVjb25vbXkiICAgICAgICAgIkFtZXJpY2EiICAgICAgICAgIkRlZmVuc2UiICAgICAgICAgIkJlbGllZiIgICAgICAgICAKIyBbNV0gIkVsZWN0aW9uIiAgICAgICAgIlBhdHJpb3Rpc20iICAgICAgIlVuaXR5IiAgICAgICAgICAgIkdvdmVybm1lbnQiICAgICAKIyBbOV0gIlJlZm9ybSIgICAgICAgICAgIlRlbXBvcmFsIiAgICAgICAgIldvcmtpbmdGYW1pbGllcyIgIkZyZWVkb20iICAgICAgICAKIyBbMTNdICJFcXVhbGl0eSIgICAgICAgICJNaXNjIiAgICAgICAgICAgICJMZWdpc2xhdGlvbiIgICAgICAgCgp0b3BpYy5wbG90PWMoMSwgMTMsIDksIDExLCA4LCAzLCA3KQpwcmludCh0b3BpY3MuaGFzaFt0b3BpYy5wbG90XSkKCmhlYXRtYXAuMihhcy5tYXRyaXgodG9waWMuc3VtbWFyeVssdG9waWMucGxvdCsxXSksIAogICAgICAgICAgc2NhbGUgPSAiY29sdW1uIiwga2V5PUYsIAogICAgICAgICAgY29sID0gYmx1ZXJlZCgxMDApLAogICAgICAgICAgY2V4Um93ID0gMC45LCBjZXhDb2wgPSAwLjksIG1hcmdpbnMgPSBjKDgsIDgpLAogICAgICAgICAgdHJhY2UgPSAibm9uZSIsIGRlbnNpdHkuaW5mbyA9ICJub25lIikKYGBgCgpgYGB7ciwgZmlnLndpZHRoPTMuMywgZmlnLmhlaWdodD01fQojIFsxXSAiRWNvbm9teSIgICAgICAgICAiQW1lcmljYSIgICAgICAgICAiRGVmZW5zZSIgICAgICAgICAiQmVsaWVmIiAgICAgICAgIAojIFs1XSAiRWxlY3Rpb24iICAgICAgICAiUGF0cmlvdGlzbSIgICAgICAiVW5pdHkiICAgICAgICAgICAiR292ZXJubWVudCIgICAgIAojIFs5XSAiUmVmb3JtIiAgICAgICAgICAiVGVtcG9yYWwiICAgICAgICAiV29ya2luZ0ZhbWlsaWVzIiAiRnJlZWRvbSIgICAgICAgIAojIFsxM10gIkVxdWFsaXR5IiAgICAgICAgIk1pc2MiICAgICAgICAgICAgIkxlZ2lzbGF0aW9uIiAgICAgICAKIAoKcGFyKG1mcm93PWMoNSwgMSksIG1hcj1jKDEsMSwyLDApLCBidHk9Im4iLCB4YXh0PSJuIiwgeWF4dD0ibiIpCgp0b3BpYy5wbG90PWMoMSwgMTMsIDE0LCAxNSwgOCwgOSwgMTIpCnByaW50KHRvcGljcy5oYXNoW3RvcGljLnBsb3RdKQoKc3BlZWNoLmRmPXRibF9kZihjb3JwdXMubGlzdC5kZiklPiVmaWx0ZXIoRmlsZT09Ikdlb3JnZUJ1c2giLCB0eXBlPT0ibm9taW4iLFRlcm09PTEpJT4lc2VsZWN0KHNlbnQuaWQsIEVjb25vbXk6TGVnaXNsYXRpb24pCnNwZWVjaC5kZj1hcy5tYXRyaXgoc3BlZWNoLmRmKQpzcGVlY2guZGZbLC0xXT1yZXBsYWNlKHNwZWVjaC5kZlssLTFdLCBzcGVlY2guZGZbLC0xXTwxLzE1LCAwLjAwMSkKc3BlZWNoLmRmWywtMV09Zi5zbW9vdGgudG9waWMoeD1zcGVlY2guZGZbLDFdLCB5PXNwZWVjaC5kZlssLTFdKQpwbG90LnN0YWNrZWQoc3BlZWNoLmRmWywxXSwgc3BlZWNoLmRmWyx0b3BpYy5wbG90KzFdLCAKICAgICAgICAgICAgIHhsYWI9IlNlbnRlbmNlcyIsIHlsYWI9IlRvcGljIHNoYXJlIiwgbWFpbj0iR2VvcmdlIEJ1c2gsIE5vbWluYXRpb24iKQoKc3BlZWNoLmRmPXRibF9kZihjb3JwdXMubGlzdC5kZiklPiVmaWx0ZXIoRmlsZT09IldpbGxpYW1KQ2xpbnRvbiIsIHR5cGU9PSJub21pbiIsIFRlcm09PTEpJT4lc2VsZWN0KHNlbnQuaWQsIEVjb25vbXk6TGVnaXNsYXRpb24pCnNwZWVjaC5kZj1hcy5tYXRyaXgoc3BlZWNoLmRmKQpzcGVlY2guZGZbLC0xXT1yZXBsYWNlKHNwZWVjaC5kZlssLTFdLCBzcGVlY2guZGZbLC0xXTwxLzE1LCAwLjAwMSkKc3BlZWNoLmRmWywtMV09Zi5zbW9vdGgudG9waWMoeD1zcGVlY2guZGZbLDFdLCB5PXNwZWVjaC5kZlssLTFdKQpwbG90LnN0YWNrZWQoc3BlZWNoLmRmWywxXSwgc3BlZWNoLmRmWyx0b3BpYy5wbG90KzFdLAogICAgICAgICAgICB4bGFiPSJTZW50ZW5jZXMiLCB5bGFiPSJUb3BpYyBzaGFyZSIsIG1haW49IkJpbGwgQ2xpbnRvbiwgTm9taW5hdGlvbiIpCgpzcGVlY2guZGY9dGJsX2RmKGNvcnB1cy5saXN0LmRmKSU+JWZpbHRlcihGaWxlPT0iR2VvcmdlV0J1c2giLCB0eXBlPT0ibm9taW4iLCBUZXJtPT0xKSU+JXNlbGVjdChzZW50LmlkLCBFY29ub215OkxlZ2lzbGF0aW9uKQpzcGVlY2guZGY9YXMubWF0cml4KHNwZWVjaC5kZikKc3BlZWNoLmRmWywtMV09cmVwbGFjZShzcGVlY2guZGZbLC0xXSwgc3BlZWNoLmRmWywtMV08MS8xNSwgMC4wMDEpCnNwZWVjaC5kZlssLTFdPWYuc21vb3RoLnRvcGljKHg9c3BlZWNoLmRmWywxXSwgeT1zcGVlY2guZGZbLC0xXSkKcGxvdC5zdGFja2VkKHNwZWVjaC5kZlssMV0sIHNwZWVjaC5kZlssdG9waWMucGxvdCsxXSwgCiAgICAgICAgICAgIHhsYWI9IlNlbnRlbmNlcyIsIHlsYWI9IlRvcGljIHNoYXJlIiwgbWFpbj0iR2VvcmdlIFcgQnVzaCwgTm9taW5hdGlvbiIpCgpzcGVlY2guZGY9dGJsX2RmKGNvcnB1cy5saXN0LmRmKSU+JWZpbHRlcihGaWxlPT0iQmFyYWNrT2JhbWEiLCB0eXBlPT0ibm9taW4iLCBUZXJtPT0xKSU+JXNlbGVjdChzZW50LmlkLCBFY29ub215OkxlZ2lzbGF0aW9uKQpzcGVlY2guZGY9YXMubWF0cml4KHNwZWVjaC5kZikKc3BlZWNoLmRmWywtMV09cmVwbGFjZShzcGVlY2guZGZbLC0xXSwgc3BlZWNoLmRmWywtMV08MS8xNSwgMC4wMDEpCnNwZWVjaC5kZlssLTFdPWYuc21vb3RoLnRvcGljKHg9c3BlZWNoLmRmWywxXSwgeT1zcGVlY2guZGZbLC0xXSkKcGxvdC5zdGFja2VkKHNwZWVjaC5kZlssMV0sIHNwZWVjaC5kZlssdG9waWMucGxvdCsxXSwKICAgICAgICAgICAgeGxhYj0iU2VudGVuY2VzIiwgeWxhYj0iVG9waWMgc2hhcmUiLCBtYWluPSJCYXJhY2sgT2JhbWEsIE5vbWluYXRpb24iKQoKc3BlZWNoLmRmPXRibF9kZihjb3JwdXMubGlzdC5kZiklPiVmaWx0ZXIoRmlsZT09IkRvbmFsZEpUcnVtcCIsIHR5cGU9PSJub21pbiIpJT4lc2VsZWN0KHNlbnQuaWQsIEVjb25vbXk6TGVnaXNsYXRpb24pCnNwZWVjaC5kZj1hcy5tYXRyaXgoc3BlZWNoLmRmKQpzcGVlY2guZGZbLC0xXT1yZXBsYWNlKHNwZWVjaC5kZlssLTFdLCBzcGVlY2guZGZbLC0xXTwxLzE1LCAwLjAwMSkKc3BlZWNoLmRmWywtMV09Zi5zbW9vdGgudG9waWMoeD1zcGVlY2guZGZbLDFdLCB5PXNwZWVjaC5kZlssLTFdKQpwbG90LnN0YWNrZWQoc3BlZWNoLmRmWywxXSwgc3BlZWNoLmRmWyx0b3BpYy5wbG90KzFdLAogICAgICAgICAgICB4bGFiPSJTZW50ZW5jZXMiLCB5bGFiPSJUb3BpYyBzaGFyZSIsIG1haW49IkRvbmFsZCBUcnVtcCwgTm9taW5hdGlvbiIpCmBgYAoKYGBge3IsIGZpZy53aWR0aD0zLjMsIGZpZy5oZWlnaHQ9NX0KIyBbMV0gIkVjb25vbXkiICAgICAgICAgIkFtZXJpY2EiICAgICAgICAgIkRlZmVuc2UiICAgICAgICAgIkJlbGllZiIgICAgICAgICAKIyBbNV0gIkVsZWN0aW9uIiAgICAgICAgIlBhdHJpb3Rpc20iICAgICAgIlVuaXR5IiAgICAgICAgICAgIkdvdmVybm1lbnQiICAgICAKIyBbOV0gIlJlZm9ybSIgICAgICAgICAgIlRlbXBvcmFsIiAgICAgICAgIldvcmtpbmdGYW1pbGllcyIgIkZyZWVkb20iICAgICAgICAKIyBbMTNdICJFcXVhbGl0eSIgICAgICAgICJNaXNjIiAgICAgICAgICAgICJMZWdpc2xhdGlvbiIgICAgICAgCgoKcGFyKG1mcm93PWMoNSwgMSksIG1hcj1jKDEsMSwyLDApLCBidHk9Im4iLCB4YXh0PSJuIiwgeWF4dD0ibiIpCgoKdG9waWMucGxvdD1jKDEsIDEzLCAxNCwgMTUsIDgsIDksIDEyKQpwcmludCh0b3BpY3MuaGFzaFt0b3BpYy5wbG90XSkKCnNwZWVjaC5kZj10YmxfZGYoY29ycHVzLmxpc3QuZGYpJT4lZmlsdGVyKEZpbGU9PSJHZW9yZ2VCdXNoIiwgdHlwZT09ImluYXVnIiwgVGVybT09MSklPiVzZWxlY3Qoc2VudC5pZCwgRWNvbm9teTpMZWdpc2xhdGlvbikKc3BlZWNoLmRmPWFzLm1hdHJpeChzcGVlY2guZGYpCnNwZWVjaC5kZlssLTFdPXJlcGxhY2Uoc3BlZWNoLmRmWywtMV0sIHNwZWVjaC5kZlssLTFdPDEvMTUsIDAuMDAxKQpzcGVlY2guZGZbLC0xXT1mLnNtb290aC50b3BpYyh4PXNwZWVjaC5kZlssMV0sIHk9c3BlZWNoLmRmWywtMV0pCnBsb3Quc3RhY2tlZChzcGVlY2guZGZbLDFdLCBzcGVlY2guZGZbLHRvcGljLnBsb3QrMV0sCiAgICAgICAgICAgICB4bGFiPSJTZW50ZW5jZXMiLCB5bGFiPSJUb3BpYyBzaGFyZSIsIG1haW49Ikdlb3JnZSBCdXNoLCBpbmF1Z3VyYWwgU3BlZWNoZXMiKQoKc3BlZWNoLmRmPXRibF9kZihjb3JwdXMubGlzdC5kZiklPiVmaWx0ZXIoRmlsZT09IldpbGxpYW1KQ2xpbnRvbiIsIHR5cGU9PSJpbmF1ZyIsIFRlcm09PTEpJT4lc2VsZWN0KHNlbnQuaWQsIEVjb25vbXk6TGVnaXNsYXRpb24pCnNwZWVjaC5kZj1hcy5tYXRyaXgoc3BlZWNoLmRmKQpzcGVlY2guZGZbLC0xXT1yZXBsYWNlKHNwZWVjaC5kZlssLTFdLCBzcGVlY2guZGZbLC0xXTwxLzE1LCAwLjAwMSkKc3BlZWNoLmRmWywtMV09Zi5zbW9vdGgudG9waWMoeD1zcGVlY2guZGZbLDFdLCB5PXNwZWVjaC5kZlssLTFdKQpwbG90LnN0YWNrZWQoc3BlZWNoLmRmWywxXSwgc3BlZWNoLmRmWyx0b3BpYy5wbG90KzFdLAogICAgICAgICAgICAgeGxhYj0iU2VudGVuY2VzIiwgeWxhYj0iVG9waWMgc2hhcmUiLCBtYWluPSJXaWxsaWFtIEogQ2xpbnRvbiwgaW5hdWd1cmFsIFNwZWVjaGVzIikKCnNwZWVjaC5kZj10YmxfZGYoY29ycHVzLmxpc3QuZGYpJT4lZmlsdGVyKEZpbGU9PSJHZW9yZ2VXQnVzaCIsIHR5cGU9PSJpbmF1ZyIsIFRlcm09PTEpJT4lc2VsZWN0KHNlbnQuaWQsIEVjb25vbXk6TGVnaXNsYXRpb24pCnNwZWVjaC5kZj1hcy5tYXRyaXgoc3BlZWNoLmRmKQpzcGVlY2guZGZbLC0xXT1yZXBsYWNlKHNwZWVjaC5kZlssLTFdLCBzcGVlY2guZGZbLC0xXTwxLzE1LCAwLjAwMSkKc3BlZWNoLmRmWywtMV09Zi5zbW9vdGgudG9waWMoeD1zcGVlY2guZGZbLDFdLCB5PXNwZWVjaC5kZlssLTFdKQpwbG90LnN0YWNrZWQoc3BlZWNoLmRmWywxXSwgc3BlZWNoLmRmWyx0b3BpYy5wbG90KzFdLAogICAgICAgICAgICAgeGxhYj0iU2VudGVuY2VzIiwgeWxhYj0iVG9waWMgc2hhcmUiLCBtYWluPSJHZW9yZ2UgVy4gQnVzaCwgaW5hdWd1cmFsIFNwZWVjaGVzIikKCnNwZWVjaC5kZj10YmxfZGYoY29ycHVzLmxpc3QuZGYpJT4lZmlsdGVyKEZpbGU9PSJCYXJhY2tPYmFtYSIsIHR5cGU9PSJpbmF1ZyIsIFRlcm09PTEpJT4lc2VsZWN0KHNlbnQuaWQsIEVjb25vbXk6TGVnaXNsYXRpb24pCnNwZWVjaC5kZj1hcy5tYXRyaXgoc3BlZWNoLmRmKQpzcGVlY2guZGZbLC0xXT1yZXBsYWNlKHNwZWVjaC5kZlssLTFdLCBzcGVlY2guZGZbLC0xXTwxLzE1LCAwLjAwMSkKc3BlZWNoLmRmWywtMV09Zi5zbW9vdGgudG9waWMoeD1zcGVlY2guZGZbLDFdLCB5PXNwZWVjaC5kZlssLTFdKQpwbG90LnN0YWNrZWQoc3BlZWNoLmRmWywxXSwgc3BlZWNoLmRmWyx0b3BpYy5wbG90KzFdLAogICAgICAgICAgICAgeGxhYj0iU2VudGVuY2VzIiwgeWxhYj0iVG9waWMgc2hhcmUiLCBtYWluPSJCYXJhY2sgT2JhbWEsIGluYXVndXJhbCBTcGVlY2hlcyIpCmBgYApgYGB7ciwgZmlnLndpZHRoPTQsIGZpZy5oZWlnaHQ9NX0KIyBbMV0gIkVjb25vbXkiICAgICAgICAgIkFtZXJpY2EiICAgICAgICAgIkRlZmVuc2UiICAgICAgICAgIkJlbGllZiIgICAgICAgICAKIyBbNV0gIkVsZWN0aW9uIiAgICAgICAgIlBhdHJpb3Rpc20iICAgICAgIlVuaXR5IiAgICAgICAgICAgIkdvdmVybm1lbnQiICAgICAKIyBbOV0gIlJlZm9ybSIgICAgICAgICAgIlRlbXBvcmFsIiAgICAgICAgIldvcmtpbmdGYW1pbGllcyIgIkZyZWVkb20iICAgICAgICAKIyBbMTNdICJFcXVhbGl0eSIgICAgICAgICJNaXNjIiAgICAgICAgICAgICJMZWdpc2xhdGlvbiIgICAgICAgCgoKcGFyKG1mcm93PWMoNSwgMSkpCgp0b3BpYy5wbG90PWMoMSwgMTMsIDE0LCAxNSwgOCwgOSwgMTIpCnByaW50KHRvcGljcy5oYXNoW3RvcGljLnBsb3RdKQoKc3BlZWNoLmRmPXRibF9kZihjb3JwdXMubGlzdC5kZiklPiVmaWx0ZXIoRmlsZT09IlJvbmFsZFJlYWdhbiIsIHR5cGU9PSJmYXJld2VsbCIpJT4lc2VsZWN0KHNlbnQuaWQsIEVjb25vbXk6TGVnaXNsYXRpb24pCnNwZWVjaC5kZj1hcy5tYXRyaXgoc3BlZWNoLmRmKQpzcGVlY2guZGZbLC0xXT1yZXBsYWNlKHNwZWVjaC5kZlssLTFdLCBzcGVlY2guZGZbLC0xXTwxLzE1LCAwLjAwMSkKc3BlZWNoLmRmWywtMV09Zi5zbW9vdGgudG9waWMoeD1zcGVlY2guZGZbLDFdLCB5PXNwZWVjaC5kZlssLTFdKQpwbG90LnN0YWNrZWQoc3BlZWNoLmRmWywxXSwgc3BlZWNoLmRmWyx0b3BpYy5wbG90KzFdLAogICAgICAgICAgICAgeGxhYj0iU2VudGVuY2VzIiwgeWxhYj0iVG9waWMgc2hhcmUiLCBtYWluPSJSb25hbGQgUmVhZ2FuLCBGYXJld2VsbCBTcGVlY2hlcyIpCgpzcGVlY2guZGY9dGJsX2RmKGNvcnB1cy5saXN0LmRmKSU+JWZpbHRlcihGaWxlPT0iR2VvcmdlQnVzaCIsIHR5cGU9PSJmYXJld2VsbCIpJT4lc2VsZWN0KHNlbnQuaWQsIEVjb25vbXk6TGVnaXNsYXRpb24pCnNwZWVjaC5kZj1hcy5tYXRyaXgoc3BlZWNoLmRmKQpzcGVlY2guZGZbLC0xXT1yZXBsYWNlKHNwZWVjaC5kZlssLTFdLCBzcGVlY2guZGZbLC0xXTwxLzE1LCAwLjAwMSkKc3BlZWNoLmRmWywtMV09Zi5zbW9vdGgudG9waWMoeD1zcGVlY2guZGZbLDFdLCB5PXNwZWVjaC5kZlssLTFdKQpwbG90LnN0YWNrZWQoc3BlZWNoLmRmWywxXSwgc3BlZWNoLmRmWyx0b3BpYy5wbG90KzFdLAogICAgICAgICAgICAgeGxhYj0iU2VudGVuY2VzIiwgeWxhYj0iVG9waWMgc2hhcmUiLCBtYWluPSJHZW9yZ2UgQnVzaCwgRmFyZXdlbGwgU3BlZWNoZXMiKQoKc3BlZWNoLmRmPXRibF9kZihjb3JwdXMubGlzdC5kZiklPiVmaWx0ZXIoRmlsZT09IldpbGxpYW1KQ2xpbnRvbiIsIHR5cGU9PSJmYXJld2VsbCIpJT4lc2VsZWN0KHNlbnQuaWQsIEVjb25vbXk6TGVnaXNsYXRpb24pCnNwZWVjaC5kZj1hcy5tYXRyaXgoc3BlZWNoLmRmKQpzcGVlY2guZGZbLC0xXT1yZXBsYWNlKHNwZWVjaC5kZlssLTFdLCBzcGVlY2guZGZbLC0xXTwxLzE1LCAwLjAwMSkKc3BlZWNoLmRmWywtMV09Zi5zbW9vdGgudG9waWMoeD1zcGVlY2guZGZbLDFdLCB5PXNwZWVjaC5kZlssLTFdKQpwbG90LnN0YWNrZWQoc3BlZWNoLmRmWywxXSwgc3BlZWNoLmRmWyx0b3BpYy5wbG90KzFdLAogICAgICAgICAgICAgeGxhYj0iU2VudGVuY2VzIiwgeWxhYj0iVG9waWMgc2hhcmUiLCBtYWluPSJXaWxsaWFtIEouIENsaW50b24sIEZhcmV3ZWxsIFNwZWVjaGVzIikKCnNwZWVjaC5kZj10YmxfZGYoY29ycHVzLmxpc3QuZGYpJT4lZmlsdGVyKEZpbGU9PSJHZW9yZ2VXQnVzaCIsIHR5cGU9PSJmYXJld2VsbCIpJT4lc2VsZWN0KHNlbnQuaWQsIEVjb25vbXk6TGVnaXNsYXRpb24pCnNwZWVjaC5kZj1hcy5tYXRyaXgoc3BlZWNoLmRmKQpzcGVlY2guZGZbLC0xXT1yZXBsYWNlKHNwZWVjaC5kZlssLTFdLCBzcGVlY2guZGZbLC0xXTwxLzE1LCAwLjAwMSkKc3BlZWNoLmRmWywtMV09Zi5zbW9vdGgudG9waWMoeD1zcGVlY2guZGZbLDFdLCB5PXNwZWVjaC5kZlssLTFdKQpwbG90LnN0YWNrZWQoc3BlZWNoLmRmWywxXSwgc3BlZWNoLmRmWyx0b3BpYy5wbG90KzFdLAogICAgICAgICAgICAgeGxhYj0iU2VudGVuY2VzIiwgeWxhYj0iVG9waWMgc2hhcmUiLCBtYWluPSJHZW9yZ2UgVyBCdXNoLCBGYXJld2VsbCBTcGVlY2hlcyIpCgoKc3BlZWNoLmRmPXRibF9kZihjb3JwdXMubGlzdC5kZiklPiVmaWx0ZXIoRmlsZT09IkJhcmFja09iYW1hIiwgdHlwZT09ImZhcmV3ZWxsIiklPiVzZWxlY3Qoc2VudC5pZCwgRWNvbm9teTpMZWdpc2xhdGlvbikKc3BlZWNoLmRmPWFzLm1hdHJpeChzcGVlY2guZGYpCnNwZWVjaC5kZlssLTFdPXJlcGxhY2Uoc3BlZWNoLmRmWywtMV0sIHNwZWVjaC5kZlssLTFdPDEvMTUsIDAuMDAxKQpzcGVlY2guZGZbLC0xXT1mLnNtb290aC50b3BpYyh4PXNwZWVjaC5kZlssMV0sIHk9c3BlZWNoLmRmWywtMV0pCnBsb3Quc3RhY2tlZChzcGVlY2guZGZbLDFdLCBzcGVlY2guZGZbLHRvcGljLnBsb3QrMV0sCiAgICAgICAgICAgICB4bGFiPSJTZW50ZW5jZXMiLCB5bGFiPSJUb3BpYyBzaGFyZSIsIG1haW49IkJhcmFjayBPYmFtYSwgRmFyZXdlbGwgU3BlZWNoZXMiKQpgYGAKCmBgYHtyfQpzcGVlY2guZGY9dGJsX2RmKGNvcnB1cy5saXN0LmRmKSU+JWZpbHRlcih0eXBlPT0ibm9taW4iLCB3b3JkLmNvdW50PDIwKSU+JXNlbGVjdChzZW50ZW5jZXMsIEVjb25vbXk6TGVnaXNsYXRpb24pCgphcy5jaGFyYWN0ZXIoc3BlZWNoLmRmJHNlbnRlbmNlc1thcHBseShhcy5kYXRhLmZyYW1lKHNwZWVjaC5kZlssLTFdKSwgMiwgd2hpY2gubWF4KV0pCgpuYW1lcyhzcGVlY2guZGYpWy0xXQoKYGBgCgoKYGBge3IsIGZpZy53aWR0aD0zLCBmaWcuaGVpZ2h0PTN9CnByZXNpZC5zdW1tYXJ5PXRibF9kZihjb3JwdXMubGlzdC5kZiklPiUKICBmaWx0ZXIodHlwZT09ImluYXVnIiwgRmlsZSVpbiVzZWwuY29tcGFyaXNvbiklPiUKICBzZWxlY3QoRmlsZSwgRWNvbm9teTpMZWdpc2xhdGlvbiklPiUKICBncm91cF9ieShGaWxlKSU+JQogIHN1bW1hcmlzZV9lYWNoKGZ1bnMobWVhbikpCgpwcmVzaWQuc3VtbWFyeT1hcy5kYXRhLmZyYW1lKHByZXNpZC5zdW1tYXJ5KQpyb3duYW1lcyhwcmVzaWQuc3VtbWFyeSk9YXMuY2hhcmFjdGVyKChwcmVzaWQuc3VtbWFyeVssMV0pKQprbS5yZXM9a21lYW5zKHNjYWxlKHByZXNpZC5zdW1tYXJ5WywtMV0pLCBpdGVyLm1heD0yMDAsCiAgICAgICAgICAgICAgNSkKZnZpel9jbHVzdGVyKGttLnJlcywgCiAgICAgICAgICAgICBzdGFuZD1ULCByZXBlbD0gVFJVRSwKICAgICAgICAgICAgIGRhdGEgPSBwcmVzaWQuc3VtbWFyeVssLTFdLAogICAgICAgICAgICAgc2hvdy5jbHVzdC5jZW50PUZBTFNFKQpgYGAKCg==